[KERNEL32]
[reactos.git] / reactos / subsystems / win / basesrv / vdm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Base API Server DLL
4 * FILE: subsystems/win/basesrv/vdm.c
5 * PURPOSE: Virtual DOS Machines (VDM) Support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "basesrv.h"
13 #include "vdm.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 BOOLEAN FirstVDM = TRUE;
21 LIST_ENTRY VDMConsoleListHead;
22 RTL_CRITICAL_SECTION DosCriticalSection;
23 RTL_CRITICAL_SECTION WowCriticalSection;
24
25 /* HELPER FUNCTIONS ***********************************************************/
26
27 PVDM_CONSOLE_RECORD BaseSrvCreateConsoleRecord(VOID)
28 {
29 PVDM_CONSOLE_RECORD ConsoleRecord;
30
31 ConsoleRecord = RtlAllocateHeap(BaseSrvHeap, HEAP_ZERO_MEMORY,
32 sizeof(VDM_CONSOLE_RECORD));
33 if (ConsoleRecord == NULL)
34 return NULL;
35
36 /* Initialize the console record */
37 ConsoleRecord->ConsoleHandle = NULL;
38 ConsoleRecord->ProcessHandle = NULL;
39 ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
40 ConsoleRecord->ReenterCount = 0;
41 ConsoleRecord->CurrentDirs = NULL;
42 ConsoleRecord->CurDirsLength = 0;
43 ConsoleRecord->SessionId = 0;
44 InitializeListHead(&ConsoleRecord->DosListHead);
45
46 return ConsoleRecord;
47 }
48
49 NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
50 {
51 PLIST_ENTRY i;
52 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
53
54 /* NULL is not a valid console handle */
55 if (ConsoleHandle == NULL) return STATUS_INVALID_PARAMETER;
56
57 /* Search for a record that has the same console handle */
58 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
59 {
60 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
61 if (CurrentRecord->ConsoleHandle == ConsoleHandle) break;
62 }
63
64 /* Check if nothing was found */
65 if (i == &VDMConsoleListHead) CurrentRecord = NULL;
66
67 *Record = CurrentRecord;
68 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
69 }
70
71 VOID BaseSrvDestroyConsoleRecord(PVDM_CONSOLE_RECORD ConsoleRecord)
72 {
73 if (ConsoleRecord->CurrentDirs != NULL)
74 {
75 /* Free the current directories */
76 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
77 ConsoleRecord->CurrentDirs = NULL;
78 ConsoleRecord->CurDirsLength = 0;
79 }
80
81 /* Close the process handle */
82 if (ConsoleRecord->ProcessHandle)
83 NtClose(ConsoleRecord->ProcessHandle);
84
85 /* Close the event handle */
86 if (ConsoleRecord->ServerEvent)
87 NtClose(ConsoleRecord->ServerEvent);
88
89 /* Remove the console record */
90 // RemoveEntryList(&ConsoleRecord->Entry);
91 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
92
93 }
94
95 NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
96 {
97 PLIST_ENTRY i;
98 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
99
100 /* Search for a record that has the same console handle */
101 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
102 {
103 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
104 if (CurrentRecord->SessionId == TaskId) break;
105 }
106
107 /* Check if nothing was found */
108 if (i == &VDMConsoleListHead) CurrentRecord = NULL;
109
110 *Record = CurrentRecord;
111 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
112 }
113
114 ULONG GetNextDosSesId(VOID)
115 {
116 ULONG SessionId;
117 PLIST_ENTRY i;
118 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
119 BOOLEAN Found;
120
121 /* Search for an available session ID */
122 for (SessionId = 1; SessionId != 0; SessionId++)
123 {
124 Found = FALSE;
125
126 /* Check if the ID is already in use */
127 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
128 {
129 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
130 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
131 }
132
133 /* If not, we found one */
134 if (!Found) break;
135 }
136
137 ASSERT(SessionId != 0);
138
139 /* Return the session ID */
140 return SessionId;
141 }
142
143 BOOLEAN BaseSrvIsVdmAllowed(VOID)
144 {
145 NTSTATUS Status;
146 BOOLEAN VdmAllowed = TRUE;
147 HANDLE RootKey, KeyHandle;
148 UNICODE_STRING KeyName, ValueName, MachineKeyName;
149 OBJECT_ATTRIBUTES Attributes;
150 UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
151 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
152 ULONG ActualSize;
153
154 /* Initialize the unicode strings */
155 RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine");
156 RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME);
157 RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME);
158
159 InitializeObjectAttributes(&Attributes,
160 &MachineKeyName,
161 OBJ_CASE_INSENSITIVE,
162 NULL,
163 NULL);
164
165 /* Open the local machine key */
166 Status = NtOpenKey(&RootKey, KEY_READ, &Attributes);
167 if (!NT_SUCCESS(Status)) return FALSE;
168
169 InitializeObjectAttributes(&Attributes,
170 &KeyName,
171 OBJ_CASE_INSENSITIVE,
172 RootKey,
173 NULL);
174
175 /* Open the policy key in the local machine hive, if it exists */
176 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
177 {
178 /* Read the value, if it's set */
179 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
180 &ValueName,
181 KeyValuePartialInformation,
182 ValueInfo,
183 sizeof(ValueBuffer),
184 &ActualSize)))
185 {
186 if (*((PULONG)ValueInfo->Data))
187 {
188 /* The VDM has been disabled in the registry */
189 VdmAllowed = FALSE;
190 }
191 }
192
193 NtClose(KeyHandle);
194 }
195
196 /* Close the local machine key */
197 NtClose(RootKey);
198
199 /* If it's disabled system-wide, there's no need to check the user key */
200 if (!VdmAllowed) return FALSE;
201
202 /* Open the current user key of the client */
203 if (!CsrImpersonateClient(NULL)) return VdmAllowed;
204 Status = RtlOpenCurrentUser(KEY_READ, &RootKey);
205 CsrRevertToSelf();
206
207 /* If that fails, return the system-wide setting */
208 if (!NT_SUCCESS(Status)) return VdmAllowed;
209
210 InitializeObjectAttributes(&Attributes,
211 &KeyName,
212 OBJ_CASE_INSENSITIVE,
213 RootKey,
214 NULL);
215
216 /* Open the policy key in the current user hive, if it exists */
217 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
218 {
219 /* Read the value, if it's set */
220 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
221 &ValueName,
222 KeyValuePartialInformation,
223 ValueInfo,
224 sizeof(ValueBuffer),
225 &ActualSize)))
226 {
227 if (*((PULONG)ValueInfo->Data))
228 {
229 /* The VDM has been disabled in the registry */
230 VdmAllowed = FALSE;
231 }
232 }
233
234 NtClose(KeyHandle);
235 }
236
237 return VdmAllowed;
238 }
239
240 NTSTATUS BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
241 {
242 NTSTATUS Status;
243
244 /* Create the event */
245 Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
246 if (!NT_SUCCESS(Status)) return Status;
247
248 /* Duplicate the event into the client process */
249 Status = NtDuplicateObject(NtCurrentProcess(),
250 *ServerEvent,
251 CsrGetClientThread()->Process->ProcessHandle,
252 ClientEvent,
253 0,
254 0,
255 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
256
257 if (!NT_SUCCESS(Status)) NtClose(*ServerEvent);
258 return Status;
259 }
260
261 VOID BaseSrvDestroyPairWaitHandles(HANDLE ServerEvent, HANDLE ClientEvent)
262 {
263 if (ServerEvent) NtClose(ServerEvent);
264 if (ClientEvent)
265 {
266 /* Close the remote handle */
267 NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
268 ClientEvent,
269 NULL,
270 NULL,
271 0,
272 0,
273 DUPLICATE_CLOSE_SOURCE);
274 }
275 }
276
277 /* WOW SUPPORT FUNCTIONS ******************************************************/
278
279 /* DOS SUPPORT FUNCTIONS ******************************************************/
280
281 VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
282 {
283 /* Free the allocated structure members */
284 if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
285 if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName);
286 if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile);
287 if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory);
288 if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env);
289 if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop);
290 if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title);
291 if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved);
292
293 /* Free the structure itself */
294 RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
295 }
296
297 VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
298 {
299 ULONG ProcessId = HandleToUlong(CsrProcess->ClientId.UniqueProcess);
300 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
301 PVDM_DOS_RECORD DosRecord;
302 PLIST_ENTRY i;
303
304 /* Enter the critical section */
305 RtlEnterCriticalSection(&DosCriticalSection);
306
307 /* Search for a record that has the same process handle */
308 i = VDMConsoleListHead.Flink;
309 while (i != &VDMConsoleListHead)
310 {
311 ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
312 i = i->Flink;
313
314 if (ConsoleRecord->ProcessId == ProcessId)
315 {
316 if (ConsoleRecord->ServerEvent)
317 {
318 NtClose(ConsoleRecord->ServerEvent);
319 ConsoleRecord->ServerEvent = NULL;
320 }
321
322 /* Cleanup the DOS records */
323 while (!IsListEmpty(&ConsoleRecord->DosListHead))
324 {
325 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
326 VDM_DOS_RECORD, Entry);
327
328 /* Set the event and close it */
329 if (DosRecord->ServerEvent)
330 {
331 NtSetEvent(DosRecord->ServerEvent, NULL);
332 NtClose(DosRecord->ServerEvent);
333 DosRecord->ServerEvent = NULL;
334 }
335
336 /* Remove the DOS entry */
337 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
338 RemoveEntryList(&DosRecord->Entry);
339 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
340 }
341
342 /* Remove the console record */
343 RemoveEntryList(&ConsoleRecord->Entry);
344 BaseSrvDestroyConsoleRecord(ConsoleRecord);
345 }
346 }
347
348 /* Leave the critical section */
349 RtlLeaveCriticalSection(&DosCriticalSection);
350 }
351
352 BOOLEAN BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
353 {
354 BOOLEAN Success = FALSE;
355 PVDM_COMMAND_INFO CommandInfo = NULL;
356
357 /* Allocate the command information structure */
358 CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap,
359 HEAP_ZERO_MEMORY,
360 sizeof(VDM_COMMAND_INFO));
361 if (CommandInfo == NULL) return FALSE;
362
363 /* Fill the structure */
364 CommandInfo->TaskId = CheckVdmRequest->iTask;
365 CommandInfo->ExitCode = DosRecord->ExitCode;
366 CommandInfo->CodePage = CheckVdmRequest->CodePage;
367 CommandInfo->StdIn = CheckVdmRequest->StdIn;
368 CommandInfo->StdOut = CheckVdmRequest->StdOut;
369 CommandInfo->StdErr = CheckVdmRequest->StdErr;
370
371 /* Allocate memory for the command line */
372 CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap,
373 HEAP_ZERO_MEMORY,
374 CheckVdmRequest->CmdLen);
375 if (CommandInfo->CmdLine == NULL) goto Cleanup;
376
377 /* Copy the command line */
378 RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen);
379
380 /* Allocate memory for the application name */
381 CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap,
382 HEAP_ZERO_MEMORY,
383 CheckVdmRequest->AppLen);
384 if (CommandInfo->AppName == NULL) goto Cleanup;
385
386 /* Copy the application name */
387 RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen);
388
389 /* Allocate memory for the PIF file name */
390 if (CheckVdmRequest->PifLen != 0)
391 {
392 CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap,
393 HEAP_ZERO_MEMORY,
394 CheckVdmRequest->PifLen);
395 if (CommandInfo->PifFile == NULL) goto Cleanup;
396
397 /* Copy the PIF file name */
398 RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen);
399 }
400 else CommandInfo->PifFile = NULL;
401
402 /* Allocate memory for the current directory */
403 if (CheckVdmRequest->CurDirectoryLen != 0)
404 {
405 CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap,
406 HEAP_ZERO_MEMORY,
407 CheckVdmRequest->CurDirectoryLen);
408 if (CommandInfo->CurDirectory == NULL) goto Cleanup;
409
410 /* Copy the current directory */
411 RtlMoveMemory(CommandInfo->CurDirectory,
412 CheckVdmRequest->CurDirectory,
413 CheckVdmRequest->CurDirectoryLen);
414 }
415 else CommandInfo->CurDirectory = NULL;
416
417 /* Allocate memory for the environment block */
418 CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap,
419 HEAP_ZERO_MEMORY,
420 CheckVdmRequest->EnvLen);
421 if (CommandInfo->Env == NULL) goto Cleanup;
422
423 /* Copy the environment block */
424 RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen);
425
426 CommandInfo->EnvLen = CheckVdmRequest->EnvLen;
427 RtlMoveMemory(&CommandInfo->StartupInfo,
428 CheckVdmRequest->StartupInfo,
429 sizeof(STARTUPINFOA));
430
431 /* Allocate memory for the desktop */
432 if (CheckVdmRequest->DesktopLen != 0)
433 {
434 CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap,
435 HEAP_ZERO_MEMORY,
436 CheckVdmRequest->DesktopLen);
437 if (CommandInfo->Desktop == NULL) goto Cleanup;
438
439 /* Copy the desktop name */
440 RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen);
441 }
442 else CommandInfo->Desktop = NULL;
443
444 CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen;
445
446 /* Allocate memory for the title */
447 if (CheckVdmRequest->TitleLen != 0)
448 {
449 CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap,
450 HEAP_ZERO_MEMORY,
451 CheckVdmRequest->TitleLen);
452 if (CommandInfo->Title == NULL) goto Cleanup;
453
454 /* Copy the title */
455 RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen);
456 }
457 else CommandInfo->Title = NULL;
458
459 CommandInfo->TitleLen = CheckVdmRequest->TitleLen;
460
461 /* Allocate memory for the reserved field */
462 if (CheckVdmRequest->ReservedLen != 0)
463 {
464 CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap,
465 HEAP_ZERO_MEMORY,
466 CheckVdmRequest->ReservedLen);
467 if (CommandInfo->Reserved == NULL) goto Cleanup;
468
469 /* Copy the reserved field */
470 RtlMoveMemory(CommandInfo->Reserved,
471 CheckVdmRequest->Reserved,
472 CheckVdmRequest->ReservedLen);
473 }
474 else CommandInfo->Reserved = NULL;
475
476 CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen;
477
478 CommandInfo->CmdLen = CheckVdmRequest->CmdLen;
479 CommandInfo->AppLen = CheckVdmRequest->AppLen;
480 CommandInfo->PifLen = CheckVdmRequest->PifLen;
481 CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen;
482 CommandInfo->VDMState = DosRecord->State;
483 // TODO: Set CommandInfo->CurrentDrive
484 // TODO: Set CommandInfo->ComingFromBat
485
486 /* Set the DOS record's command structure */
487 DosRecord->CommandInfo = CommandInfo;
488
489 /* The operation was successful */
490 Success = TRUE;
491
492 Cleanup:
493 /* If it wasn't successful, free the memory */
494 if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
495
496 return Success;
497 }
498
499 NTSTATUS BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
500 PBASE_GET_NEXT_VDM_COMMAND Message)
501 {
502 NTSTATUS Status = STATUS_SUCCESS;
503
504 /* Copy the data */
505 Message->iTask = CommandInfo->TaskId;
506 Message->StdIn = CommandInfo->StdIn;
507 Message->StdOut = CommandInfo->StdOut;
508 Message->StdErr = CommandInfo->StdErr;
509 Message->CodePage = CommandInfo->CodePage;
510 Message->dwCreationFlags = CommandInfo->CreationFlags;
511 Message->ExitCode = CommandInfo->ExitCode;
512 Message->CurrentDrive = CommandInfo->CurrentDrive;
513 Message->VDMState = CommandInfo->VDMState;
514 Message->fComingFromBat = CommandInfo->ComingFromBat;
515
516 if (Message->CmdLen >= CommandInfo->CmdLen)
517 {
518 /* Copy the command line */
519 RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
520 }
521 else Status = STATUS_INVALID_PARAMETER;
522 Message->CmdLen = CommandInfo->CmdLen;
523
524 if (Message->AppLen >= CommandInfo->AppLen)
525 {
526 /* Copy the application name */
527 RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
528 }
529 else Status = STATUS_INVALID_PARAMETER;
530 Message->AppLen = CommandInfo->AppLen;
531
532 if (Message->PifLen >= CommandInfo->PifLen)
533 {
534 /* Copy the PIF file name */
535 RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
536 }
537 else Status = STATUS_INVALID_PARAMETER;
538 Message->PifLen = CommandInfo->PifLen;
539
540 if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen)
541 {
542 /* Copy the current directory */
543 RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
544 }
545 else Status = STATUS_INVALID_PARAMETER;
546 Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
547
548 if (Message->EnvLen >= CommandInfo->EnvLen)
549 {
550 /* Copy the environment */
551 RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
552 }
553 else Status = STATUS_INVALID_PARAMETER;
554 Message->EnvLen = CommandInfo->EnvLen;
555
556 /* Copy the startup info */
557 RtlMoveMemory(Message->StartupInfo,
558 &CommandInfo->StartupInfo,
559 sizeof(STARTUPINFOA));
560
561 if (Message->DesktopLen >= CommandInfo->DesktopLen)
562 {
563 /* Copy the desktop name */
564 RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
565 }
566 else Status = STATUS_INVALID_PARAMETER;
567 Message->DesktopLen = CommandInfo->DesktopLen;
568
569 if (Message->TitleLen >= CommandInfo->TitleLen)
570 {
571 /* Copy the title */
572 RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
573 }
574 else Status = STATUS_INVALID_PARAMETER;
575 Message->TitleLen = CommandInfo->TitleLen;
576
577 if (Message->ReservedLen >= CommandInfo->ReservedLen)
578 {
579 /* Copy the reserved parameter */
580 RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
581 }
582 else Status = STATUS_INVALID_PARAMETER;
583 Message->ReservedLen = CommandInfo->ReservedLen;
584
585 return Status;
586 }
587
588 VOID BaseInitializeVDM(VOID)
589 {
590 /* Initialize the list head */
591 InitializeListHead(&VDMConsoleListHead);
592
593 /* Initialize the critical sections */
594 RtlInitializeCriticalSection(&DosCriticalSection);
595 RtlInitializeCriticalSection(&WowCriticalSection);
596 }
597
598 /* PUBLIC SERVER APIS *********************************************************/
599
600 CSR_API(BaseSrvCheckVDM)
601 {
602 NTSTATUS Status;
603 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
604 PRTL_CRITICAL_SECTION CriticalSection = NULL;
605 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
606 PVDM_DOS_RECORD DosRecord = NULL;
607 BOOLEAN NewConsoleRecord = FALSE;
608 BOOLEAN NewDosRecord = FALSE;
609
610 /* Don't do anything if the VDM has been disabled in the registry */
611 if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED;
612
613 /* Validate the message buffers */
614 if (!CsrValidateMessageBuffer(ApiMessage,
615 (PVOID*)&CheckVdmRequest->CmdLine,
616 CheckVdmRequest->CmdLen,
617 sizeof(*CheckVdmRequest->CmdLine))
618 || !CsrValidateMessageBuffer(ApiMessage,
619 (PVOID*)&CheckVdmRequest->AppName,
620 CheckVdmRequest->AppLen,
621 sizeof(*CheckVdmRequest->AppName))
622 || !CsrValidateMessageBuffer(ApiMessage,
623 (PVOID*)&CheckVdmRequest->PifFile,
624 CheckVdmRequest->PifLen,
625 sizeof(*CheckVdmRequest->PifFile))
626 || !CsrValidateMessageBuffer(ApiMessage,
627 (PVOID*)&CheckVdmRequest->CurDirectory,
628 CheckVdmRequest->CurDirectoryLen,
629 sizeof(*CheckVdmRequest->CurDirectory))
630 || !CsrValidateMessageBuffer(ApiMessage,
631 (PVOID*)&CheckVdmRequest->Desktop,
632 CheckVdmRequest->DesktopLen,
633 sizeof(*CheckVdmRequest->Desktop))
634 || !CsrValidateMessageBuffer(ApiMessage,
635 (PVOID*)&CheckVdmRequest->Title,
636 CheckVdmRequest->TitleLen,
637 sizeof(*CheckVdmRequest->Title))
638 || !CsrValidateMessageBuffer(ApiMessage,
639 (PVOID*)&CheckVdmRequest->Reserved,
640 CheckVdmRequest->ReservedLen,
641 sizeof(*CheckVdmRequest->Reserved)))
642 {
643 return STATUS_INVALID_PARAMETER;
644 }
645
646 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
647 ? &DosCriticalSection
648 : &WowCriticalSection;
649
650 /* Enter the critical section */
651 RtlEnterCriticalSection(CriticalSection);
652
653 /* Check if this is a DOS or WOW VDM */
654 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
655 {
656 /* Get the console record */
657 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
658 &ConsoleRecord);
659 if (!NT_SUCCESS(Status))
660 {
661 /* Allocate a new console record */
662 ConsoleRecord = BaseSrvCreateConsoleRecord();
663 if (ConsoleRecord == NULL)
664 {
665 Status = STATUS_NO_MEMORY;
666 goto Cleanup;
667 }
668
669 /* Initialize the console record */
670 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
671 if (ConsoleRecord->ConsoleHandle == NULL)
672 {
673 /* The parent doesn't have a console, get a new session ID */
674 ConsoleRecord->SessionId = GetNextDosSesId();
675 }
676 else
677 {
678 /* No session ID is needed */
679 ConsoleRecord->SessionId = 0;
680 }
681
682 /* Remember that the console record was allocated here */
683 NewConsoleRecord = TRUE;
684 }
685
686 if (!NewConsoleRecord)
687 {
688 /* Get the primary DOS record */
689 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
690 VDM_DOS_RECORD, Entry);
691
692 if (DosRecord->State != VDM_READY) // == VDM_NOT_READY
693 {
694 /* Allocate a new DOS record */
695 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
696 HEAP_ZERO_MEMORY,
697 sizeof(VDM_DOS_RECORD));
698 if (DosRecord == NULL)
699 {
700 Status = STATUS_NO_MEMORY;
701 goto Cleanup;
702 }
703
704 /* Remember that the DOS record was allocated here */
705 NewDosRecord = TRUE;
706 }
707 }
708 else
709 {
710 /* Allocate a new DOS record */
711 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
712 HEAP_ZERO_MEMORY,
713 sizeof(VDM_DOS_RECORD));
714 if (DosRecord == NULL)
715 {
716 Status = STATUS_NO_MEMORY;
717 goto Cleanup;
718 }
719
720 /* Remember that the DOS record was allocated here */
721 NewDosRecord = TRUE;
722 }
723
724 /* Initialize the DOS record */
725 DosRecord->State = VDM_NOT_READY;
726 DosRecord->ExitCode = 0;
727
728 /* Translate the input structure into a VDM command structure and set it in the DOS record */
729 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
730 {
731 /* The only possibility is that an allocation failure occurred */
732 Status = STATUS_NO_MEMORY;
733 goto Cleanup;
734 }
735
736 if (NewDosRecord)
737 {
738 /* Add the DOS record */
739 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
740 }
741
742 if (!NewConsoleRecord)
743 {
744 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
745 if (!NT_SUCCESS(Status)) goto Cleanup;
746
747 /* Return the client event handle */
748 CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
749 }
750
751 // FIXME: We may notify ONLY if ConsoleRecord->nReEntrancy is > 0
752 // in case NewConsoleRecord == FALSE AND NewDosRecord == TRUE.
753 if (ConsoleRecord->ServerEvent)
754 {
755 /* Signal the session event */
756 NtSetEvent(ConsoleRecord->ServerEvent, NULL);
757 }
758
759 if (NewConsoleRecord)
760 {
761 /* Add the console record */
762 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
763 }
764
765 CheckVdmRequest->iTask = ConsoleRecord->SessionId;
766 CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
767 Status = STATUS_SUCCESS;
768 }
769 else
770 {
771 // TODO: NOT IMPLEMENTED
772 UNIMPLEMENTED;
773 Status = STATUS_NOT_IMPLEMENTED;
774 }
775
776 Cleanup:
777 /* Check if it failed */
778 if (!NT_SUCCESS(Status))
779 {
780 /* Free the DOS record if it was allocated here */
781 if (NewDosRecord)
782 {
783 ASSERT(DosRecord != NULL);
784
785 BaseSrvDestroyPairWaitHandles(DosRecord->ServerEvent,
786 DosRecord->ClientEvent);
787
788 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
789 DosRecord = NULL;
790 }
791
792 /* Free the console record if it was allocated here */
793 if (NewConsoleRecord)
794 {
795 ASSERT(ConsoleRecord != NULL);
796
797 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
798 ConsoleRecord = NULL;
799 }
800 }
801
802 /* Leave the critical section */
803 RtlLeaveCriticalSection(CriticalSection);
804
805 return Status;
806 }
807
808 CSR_API(BaseSrvUpdateVDMEntry)
809 {
810 NTSTATUS Status;
811 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest;
812 PRTL_CRITICAL_SECTION CriticalSection = NULL;
813 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
814 PVDM_DOS_RECORD DosRecord = NULL;
815
816 CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
817 ? &DosCriticalSection
818 : &WowCriticalSection;
819
820 /* Enter the critical section */
821 RtlEnterCriticalSection(CriticalSection);
822
823 /* Check if this is a DOS or WOW VDM */
824 if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
825 {
826 if (UpdateVdmEntryRequest->iTask != 0)
827 {
828 /* Get the console record using the task ID */
829 Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask,
830 &ConsoleRecord);
831 }
832 else
833 {
834 /* Get the console record using the console handle */
835 Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle,
836 &ConsoleRecord);
837 }
838
839 if (!NT_SUCCESS(Status)) goto Cleanup;
840
841 /* Get the primary DOS record */
842 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
843 VDM_DOS_RECORD, Entry);
844
845 switch (UpdateVdmEntryRequest->EntryIndex)
846 {
847 case VdmEntryUndo:
848 {
849 /* Close the server event handle, the client will close the client handle */
850 NtClose(DosRecord->ServerEvent);
851 DosRecord->ServerEvent = DosRecord->ClientEvent = NULL;
852
853 if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL))
854 {
855 /* Remove the DOS record */
856 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
857 RemoveEntryList(&DosRecord->Entry);
858 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
859
860 /*
861 * Since this is an undo, if that was the only DOS record the VDM
862 * won't even start, so the console record should be removed too.
863 */
864 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
865 {
866 RemoveEntryList(&ConsoleRecord->Entry);
867 BaseSrvDestroyConsoleRecord(ConsoleRecord);
868 }
869 }
870
871 /* It was successful */
872 Status = STATUS_SUCCESS;
873
874 break;
875 }
876
877 case VdmEntryUpdateProcess:
878 {
879 /* Duplicate the VDM process handle */
880 Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
881 UpdateVdmEntryRequest->VDMProcessHandle,
882 NtCurrentProcess(),
883 &ConsoleRecord->ProcessHandle,
884 0,
885 0,
886 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
887 if (!NT_SUCCESS(Status)) goto Cleanup;
888
889 //
890 // FIXME! Should we always do the following??
891 //
892
893 /* Create a pair of handles to one event object */
894 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
895 &DosRecord->ClientEvent);
896 if (!NT_SUCCESS(Status)) goto Cleanup;
897
898 /* Return the client event handle */
899 UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent;
900
901 break;
902 }
903
904 case VdmEntryUpdateControlCHandler:
905 {
906 // TODO: NOT IMPLEMENTED
907 DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!");
908 Status = STATUS_NOT_IMPLEMENTED;
909
910 break;
911 }
912
913 default:
914 {
915 /* Invalid */
916 Status = STATUS_INVALID_PARAMETER;
917 }
918 }
919 }
920 else
921 {
922 // TODO: NOT IMPLEMENTED
923 UNIMPLEMENTED;
924 Status = STATUS_NOT_IMPLEMENTED;
925 }
926
927 Cleanup:
928 /* Leave the critical section */
929 RtlLeaveCriticalSection(CriticalSection);
930
931 return Status;
932 }
933
934 CSR_API(BaseSrvGetNextVDMCommand)
935 {
936 NTSTATUS Status;
937 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
938 &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
939 PRTL_CRITICAL_SECTION CriticalSection;
940 PLIST_ENTRY i = NULL;
941 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
942 PVDM_DOS_RECORD DosRecord = NULL;
943
944 /* Validate the message buffers */
945 if (!CsrValidateMessageBuffer(ApiMessage,
946 (PVOID*)&GetNextVdmCommandRequest->CmdLine,
947 GetNextVdmCommandRequest->CmdLen,
948 sizeof(*GetNextVdmCommandRequest->CmdLine))
949 || !CsrValidateMessageBuffer(ApiMessage,
950 (PVOID*)&GetNextVdmCommandRequest->AppName,
951 GetNextVdmCommandRequest->AppLen,
952 sizeof(*GetNextVdmCommandRequest->AppName))
953 || !CsrValidateMessageBuffer(ApiMessage,
954 (PVOID*)&GetNextVdmCommandRequest->PifFile,
955 GetNextVdmCommandRequest->PifLen,
956 sizeof(*GetNextVdmCommandRequest->PifFile))
957 || !CsrValidateMessageBuffer(ApiMessage,
958 (PVOID*)&GetNextVdmCommandRequest->CurDirectory,
959 GetNextVdmCommandRequest->CurDirectoryLen,
960 sizeof(*GetNextVdmCommandRequest->CurDirectory))
961 || !CsrValidateMessageBuffer(ApiMessage,
962 (PVOID*)&GetNextVdmCommandRequest->Env,
963 GetNextVdmCommandRequest->EnvLen,
964 sizeof(*GetNextVdmCommandRequest->Env))
965 || !CsrValidateMessageBuffer(ApiMessage,
966 (PVOID*)&GetNextVdmCommandRequest->Desktop,
967 GetNextVdmCommandRequest->DesktopLen,
968 sizeof(*GetNextVdmCommandRequest->Desktop))
969 || !CsrValidateMessageBuffer(ApiMessage,
970 (PVOID*)&GetNextVdmCommandRequest->Title,
971 GetNextVdmCommandRequest->TitleLen,
972 sizeof(*GetNextVdmCommandRequest->Title))
973 || !CsrValidateMessageBuffer(ApiMessage,
974 (PVOID*)&GetNextVdmCommandRequest->Reserved,
975 GetNextVdmCommandRequest->ReservedLen,
976 sizeof(*GetNextVdmCommandRequest->Reserved))
977 || !CsrValidateMessageBuffer(ApiMessage,
978 (PVOID*)&GetNextVdmCommandRequest->StartupInfo,
979 1,
980 sizeof(STARTUPINFOA)))
981 {
982 return STATUS_INVALID_PARAMETER;
983 }
984
985 CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
986 ? &WowCriticalSection
987 : &DosCriticalSection;
988
989 /* Enter the critical section */
990 RtlEnterCriticalSection(CriticalSection);
991
992 if (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
993 {
994 // TODO: WOW SUPPORT NOT IMPLEMENTED
995 UNIMPLEMENTED;
996 Status = STATUS_NOT_IMPLEMENTED;
997 goto Cleanup;
998 }
999 // else if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
1000 {
1001 if (GetNextVdmCommandRequest->iTask != 0)
1002 {
1003 /* Get the console record using the task ID */
1004 Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask,
1005 &ConsoleRecord);
1006 }
1007 else
1008 {
1009 /* Get the console record using the console handle */
1010 Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle,
1011 &ConsoleRecord);
1012 }
1013
1014 /* Make sure we found the console record */
1015 if (!NT_SUCCESS(Status)) goto Cleanup;
1016
1017 /* Return the session ID */
1018 GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
1019 GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
1020
1021 if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND)
1022 {
1023 /* Check if the DOS record list is empty */
1024 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
1025 {
1026 Status = STATUS_INVALID_PARAMETER;
1027 goto Cleanup;
1028 }
1029
1030 /* Get the first DOS record */
1031 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry);
1032
1033 /* Make sure its command information is still there */
1034 if (DosRecord->CommandInfo == NULL)
1035 {
1036 Status = STATUS_INVALID_PARAMETER;
1037 goto Cleanup;
1038 }
1039
1040 /* Check if the console handle hasn't been set yet */
1041 if (ConsoleRecord->ConsoleHandle == NULL)
1042 {
1043 /* Set it now */
1044 ConsoleRecord->ConsoleHandle = GetNextVdmCommandRequest->ConsoleHandle;
1045 }
1046
1047 /* Fill the command information */
1048 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
1049 goto Cleanup;
1050 }
1051
1052 /* Check if we should set the state of a running DOS record to ready */
1053 if (!(GetNextVdmCommandRequest->VDMState
1054 & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK)))
1055 {
1056 /* Search for a DOS record that is currently running */
1057 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1058 {
1059 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1060 if (DosRecord->State == VDM_NOT_READY) break;
1061 }
1062
1063 /* Check if we found any */
1064 if (i == &ConsoleRecord->DosListHead)
1065 {
1066 Status = STATUS_INVALID_PARAMETER;
1067 goto Cleanup;
1068 }
1069
1070 /* Set the exit code */
1071 DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode;
1072
1073 /* Update the VDM state */
1074 DosRecord->State = VDM_READY;
1075
1076 /* Notify all waiting threads that the task is finished */
1077 NtSetEvent(DosRecord->ServerEvent, NULL);
1078 NtClose(DosRecord->ServerEvent);
1079 DosRecord->ServerEvent = NULL;
1080 }
1081
1082 /* Search for a DOS record that is currently running and has command information */
1083 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1084 {
1085 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1086 if ((DosRecord->State == VDM_NOT_READY) && (DosRecord->CommandInfo != NULL)) break;
1087 }
1088
1089 /* Check if we found any */
1090 if (i != &ConsoleRecord->DosListHead)
1091 {
1092 ASSERT(DosRecord->CommandInfo != NULL);
1093
1094 /* Check if the caller only wants environment data */
1095 if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT)
1096 {
1097 if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen)
1098 {
1099 /* Not enough space was reserved */
1100 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
1101 Status = STATUS_BUFFER_OVERFLOW;
1102 goto Cleanup;
1103 }
1104
1105 /* Copy the environment data */
1106 RtlMoveMemory(GetNextVdmCommandRequest->Env,
1107 DosRecord->CommandInfo->Env,
1108 DosRecord->CommandInfo->EnvLen);
1109
1110 /* Return the actual size to the caller */
1111 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
1112 }
1113 else
1114 {
1115 /* Fill the command information */
1116 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
1117 if (!NT_SUCCESS(Status)) goto Cleanup;
1118
1119 /* Free the command information, it's no longer needed */
1120 BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1121 DosRecord->CommandInfo = NULL;
1122
1123 /* Update the VDM state */
1124 DosRecord->State = VDM_NOT_READY;
1125 }
1126
1127 Status = STATUS_SUCCESS;
1128 goto Cleanup;
1129 }
1130 }
1131
1132 GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
1133
1134 /*
1135 * There is no command yet. Prepare for waiting if we asked so,
1136 * and if we were not retrying a request.
1137 */
1138 if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT) ||
1139 !(GetNextVdmCommandRequest->VDMState & VDM_FLAG_RETRY))
1140 {
1141 if (ConsoleRecord->ServerEvent)
1142 {
1143 /* Reset the event */
1144 NtResetEvent(ConsoleRecord->ServerEvent, NULL);
1145 }
1146 else
1147 {
1148 /* Create a pair of wait handles */
1149 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
1150 &ConsoleRecord->ClientEvent);
1151 if (!NT_SUCCESS(Status)) goto Cleanup;
1152 }
1153
1154 /* Return the client event handle */
1155 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
1156 }
1157
1158 Cleanup:
1159 /* Leave the critical section */
1160 RtlLeaveCriticalSection(CriticalSection);
1161
1162 return Status;
1163 }
1164
1165 CSR_API(BaseSrvExitVDM)
1166 {
1167 NTSTATUS Status;
1168 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
1169 PRTL_CRITICAL_SECTION CriticalSection = NULL;
1170 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1171 PVDM_DOS_RECORD DosRecord;
1172
1173 CriticalSection = (ExitVdmRequest->iWowTask == 0)
1174 ? &DosCriticalSection
1175 : &WowCriticalSection;
1176
1177 /* Enter the critical section */
1178 RtlEnterCriticalSection(CriticalSection);
1179
1180 if (ExitVdmRequest->iWowTask == 0)
1181 {
1182 /* Get the console record */
1183 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
1184 if (!NT_SUCCESS(Status)) goto Cleanup;
1185
1186 if (ConsoleRecord->ServerEvent)
1187 ExitVdmRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
1188
1189 // NOTE: The following is the same as in BaseSrvCleanupVDMResources.
1190
1191 if (ConsoleRecord->ServerEvent)
1192 {
1193 NtClose(ConsoleRecord->ServerEvent);
1194 ConsoleRecord->ServerEvent = NULL;
1195 }
1196
1197 /* Cleanup the DOS records */
1198 while (!IsListEmpty(&ConsoleRecord->DosListHead))
1199 {
1200 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
1201 VDM_DOS_RECORD, Entry);
1202
1203 /* Set the event and close it */
1204 if (DosRecord->ServerEvent)
1205 {
1206 NtSetEvent(DosRecord->ServerEvent, NULL);
1207 NtClose(DosRecord->ServerEvent);
1208 DosRecord->ServerEvent = NULL;
1209 }
1210
1211 /* Remove the DOS entry */
1212 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1213 RemoveEntryList(&DosRecord->Entry);
1214 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1215 }
1216
1217 /* Remove the console record */
1218 RemoveEntryList(&ConsoleRecord->Entry);
1219 BaseSrvDestroyConsoleRecord(ConsoleRecord);
1220 }
1221 else
1222 {
1223 // TODO: NOT IMPLEMENTED
1224 UNIMPLEMENTED;
1225 Status = STATUS_NOT_IMPLEMENTED;
1226 }
1227
1228 Cleanup:
1229 /* Leave the critical section */
1230 RtlLeaveCriticalSection(CriticalSection);
1231
1232 return Status;
1233 }
1234
1235 CSR_API(BaseSrvIsFirstVDM)
1236 {
1237 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
1238
1239 /* Return the result */
1240 IsFirstVDMRequest->FirstVDM = FirstVDM;
1241
1242 /* Clear the first VDM flag */
1243 FirstVDM = FALSE;
1244
1245 return STATUS_SUCCESS;
1246 }
1247
1248 CSR_API(BaseSrvGetVDMExitCode)
1249 {
1250 NTSTATUS Status;
1251 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
1252 PLIST_ENTRY i = NULL;
1253 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1254 PVDM_DOS_RECORD DosRecord = NULL;
1255
1256 /* Enter the critical section */
1257 RtlEnterCriticalSection(&DosCriticalSection);
1258
1259 /* Get the console record */
1260 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
1261 if (!NT_SUCCESS(Status)) goto Cleanup;
1262
1263 /* Search for a DOS record that has the same parent process handle */
1264 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1265 {
1266 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1267 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
1268 }
1269
1270 /* Check if no DOS record was found */
1271 if (i == &ConsoleRecord->DosListHead)
1272 {
1273 Status = STATUS_NOT_FOUND;
1274 goto Cleanup;
1275 }
1276
1277 /* Check if this task is still running */
1278 if (DosRecord->State != VDM_READY)
1279 {
1280 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
1281 goto Cleanup;
1282 }
1283
1284 /* Return the exit code */
1285 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
1286
1287 // FIXME: We may just change DosRecord->State to VDM_READY in some cases...
1288
1289 /* Since this is a zombie task record, remove it */
1290 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1291 RemoveEntryList(&DosRecord->Entry);
1292 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1293
1294 Cleanup:
1295 /* Leave the critical section */
1296 RtlLeaveCriticalSection(&DosCriticalSection);
1297
1298 return Status;
1299 }
1300
1301 CSR_API(BaseSrvSetReenterCount)
1302 {
1303 NTSTATUS Status = STATUS_SUCCESS;
1304 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
1305 PVDM_CONSOLE_RECORD ConsoleRecord;
1306
1307 /* Enter the critical section */
1308 RtlEnterCriticalSection(&DosCriticalSection);
1309
1310 /* Get the console record */
1311 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
1312 if (!NT_SUCCESS(Status)) goto Cleanup;
1313
1314 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT)
1315 {
1316 ConsoleRecord->ReenterCount++;
1317 }
1318 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
1319 {
1320 ConsoleRecord->ReenterCount--;
1321 if (ConsoleRecord->ServerEvent)
1322 NtSetEvent(ConsoleRecord->ServerEvent, NULL);
1323 }
1324 else
1325 {
1326 Status = STATUS_INVALID_PARAMETER;
1327 }
1328
1329 Cleanup:
1330 /* Leave the critical section */
1331 RtlLeaveCriticalSection(&DosCriticalSection);
1332
1333 return Status;
1334 }
1335
1336 CSR_API(BaseSrvSetVDMCurDirs)
1337 {
1338 NTSTATUS Status;
1339 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1340 PVDM_CONSOLE_RECORD ConsoleRecord;
1341 PCHAR Buffer = NULL;
1342
1343 /* Validate the input buffer */
1344 if (!CsrValidateMessageBuffer(ApiMessage,
1345 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1346 VDMCurrentDirsRequest->cchCurDirs,
1347 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1348 {
1349 return STATUS_INVALID_PARAMETER;
1350 }
1351
1352 /* Enter the critical section */
1353 RtlEnterCriticalSection(&DosCriticalSection);
1354
1355 /* Find the console record */
1356 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1357 if (!NT_SUCCESS(Status)) goto Cleanup;
1358
1359 if (ConsoleRecord->CurrentDirs == NULL)
1360 {
1361 /* Allocate memory for the current directory information */
1362 Buffer = RtlAllocateHeap(BaseSrvHeap,
1363 HEAP_ZERO_MEMORY,
1364 VDMCurrentDirsRequest->cchCurDirs);
1365 }
1366 else
1367 {
1368 /* Resize the amount of allocated memory */
1369 Buffer = RtlReAllocateHeap(BaseSrvHeap,
1370 HEAP_ZERO_MEMORY,
1371 ConsoleRecord->CurrentDirs,
1372 VDMCurrentDirsRequest->cchCurDirs);
1373 }
1374
1375 if (Buffer == NULL)
1376 {
1377 /* Allocation failed */
1378 Status = STATUS_NO_MEMORY;
1379 goto Cleanup;
1380 }
1381
1382 /* Update the console record */
1383 ConsoleRecord->CurrentDirs = Buffer;
1384 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
1385
1386 /* Copy the data */
1387 RtlMoveMemory(ConsoleRecord->CurrentDirs,
1388 VDMCurrentDirsRequest->lpszzCurDirs,
1389 VDMCurrentDirsRequest->cchCurDirs);
1390
1391 Cleanup:
1392 /* Leave the critical section */
1393 RtlLeaveCriticalSection(&DosCriticalSection);
1394
1395 return Status;
1396 }
1397
1398 CSR_API(BaseSrvGetVDMCurDirs)
1399 {
1400 NTSTATUS Status;
1401 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1402 PVDM_CONSOLE_RECORD ConsoleRecord;
1403
1404 /* Validate the output buffer */
1405 if (!CsrValidateMessageBuffer(ApiMessage,
1406 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1407 VDMCurrentDirsRequest->cchCurDirs,
1408 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1409 {
1410 return STATUS_INVALID_PARAMETER;
1411 }
1412
1413 /* Enter the critical section */
1414 RtlEnterCriticalSection(&DosCriticalSection);
1415
1416 /* Find the console record */
1417 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1418 if (!NT_SUCCESS(Status)) goto Cleanup;
1419
1420 /* Return the actual size of the current directory information */
1421 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
1422
1423 /* Check if the buffer is large enough */
1424 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
1425 {
1426 Status = STATUS_BUFFER_TOO_SMALL;
1427 goto Cleanup;
1428 }
1429
1430 /* Copy the data */
1431 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
1432 ConsoleRecord->CurrentDirs,
1433 ConsoleRecord->CurDirsLength);
1434
1435 Cleanup:
1436 /* Leave the critical section */
1437 RtlLeaveCriticalSection(&DosCriticalSection);
1438
1439 return Status;
1440 }
1441
1442 CSR_API(BaseSrvBatNotification)
1443 {
1444 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1445 return STATUS_NOT_IMPLEMENTED;
1446 }
1447
1448 CSR_API(BaseSrvRegisterWowExec)
1449 {
1450 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1451 return STATUS_NOT_IMPLEMENTED;
1452 }
1453
1454 CSR_API(BaseSrvRefreshIniFileMapping)
1455 {
1456 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1457 return STATUS_NOT_IMPLEMENTED;
1458 }
1459
1460 /* EOF */