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