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