2493120fdf8989553cc1ebf224df404ce6cf09e3
[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 /* Check if the console handle hasn't been set yet */
980 if (ConsoleRecord->ConsoleHandle == NULL)
981 {
982 /* Set it now */
983 ConsoleRecord->ConsoleHandle = GetNextVdmCommandRequest->ConsoleHandle;
984 }
985
986 /* Fill the command information */
987 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
988 goto Cleanup;
989 }
990
991 /* Check if we should set the state of a running DOS record to ready */
992 if (!(GetNextVdmCommandRequest->VDMState
993 & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK)))
994 {
995 /* Search for a DOS record that is currently running */
996 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
997 {
998 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
999 if (DosRecord->State == VDM_NOT_READY) break;
1000 }
1001
1002 /* Check if we found any */
1003 if (i == &ConsoleRecord->DosListHead)
1004 {
1005 Status = STATUS_INVALID_PARAMETER;
1006 goto Cleanup;
1007 }
1008
1009 /* Set the exit code */
1010 DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode;
1011
1012 /* Update the VDM state */
1013 DosRecord->State = VDM_READY;
1014
1015 /* Notify all waiting threads that the task is finished */
1016 NtSetEvent(DosRecord->ServerEvent, NULL);
1017 NtClose(DosRecord->ServerEvent);
1018 DosRecord->ServerEvent = NULL;
1019 }
1020
1021 /* Search for a DOS record that isn't loaded yet */
1022 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1023 {
1024 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1025 if (DosRecord->State == VDM_NOT_LOADED) break;
1026 }
1027
1028 if (i != &ConsoleRecord->DosListHead)
1029 {
1030 /* DOS tasks which haven't been loaded yet should have a command info structure */
1031 ASSERT(DosRecord->CommandInfo != NULL);
1032
1033 /* Check if the caller only wants environment data */
1034 if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT)
1035 {
1036 if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen)
1037 {
1038 /* Not enough space was reserved */
1039 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
1040 Status = STATUS_BUFFER_OVERFLOW;
1041 goto Cleanup;
1042 }
1043
1044 /* Copy the environment data */
1045 RtlMoveMemory(GetNextVdmCommandRequest->Env,
1046 DosRecord->CommandInfo->Env,
1047 DosRecord->CommandInfo->EnvLen);
1048
1049 /* Return the actual size to the caller */
1050 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
1051 }
1052 else
1053 {
1054 /* Fill the command information */
1055 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
1056 if (!NT_SUCCESS(Status)) goto Cleanup;
1057
1058 /* Free the command information, it's no longer needed */
1059 BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1060 DosRecord->CommandInfo = NULL;
1061
1062 /* Update the VDM state */
1063 GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY;
1064 }
1065
1066 Status = STATUS_SUCCESS;
1067 goto Cleanup;
1068 }
1069 }
1070 else
1071 {
1072 // TODO: WOW SUPPORT NOT IMPLEMENTED
1073 Status = STATUS_NOT_IMPLEMENTED;
1074 goto Cleanup;
1075 }
1076
1077 /* There is no command yet */
1078 if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT))
1079 {
1080 if (ConsoleRecord->ServerEvent)
1081 {
1082 /* Reset the event */
1083 NtResetEvent(ConsoleRecord->ServerEvent, NULL);
1084 }
1085 else
1086 {
1087 /* Create a pair of wait handles */
1088 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
1089 &ConsoleRecord->ClientEvent);
1090 if (!NT_SUCCESS(Status)) goto Cleanup;
1091 }
1092
1093 /* Return the client event handle */
1094 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
1095 }
1096
1097 Cleanup:
1098 /* Leave the critical section */
1099 RtlLeaveCriticalSection(CriticalSection);
1100
1101 return Status;
1102 }
1103
1104 CSR_API(BaseSrvExitVDM)
1105 {
1106 NTSTATUS Status;
1107 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
1108 PRTL_CRITICAL_SECTION CriticalSection = NULL;
1109 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1110 PVDM_DOS_RECORD DosRecord;
1111
1112 CriticalSection = (ExitVdmRequest->iWowTask == 0)
1113 ? &DosCriticalSection
1114 : &WowCriticalSection;
1115
1116 /* Enter the critical section */
1117 RtlEnterCriticalSection(CriticalSection);
1118
1119 if (ExitVdmRequest->iWowTask == 0)
1120 {
1121 /* Get the console record */
1122 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
1123 if (!NT_SUCCESS(Status)) goto Cleanup;
1124
1125 /* Cleanup the DOS records */
1126 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
1127 {
1128 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
1129 VDM_DOS_RECORD,
1130 Entry);
1131
1132 /* Set the event and close it */
1133 NtSetEvent(DosRecord->ServerEvent, NULL);
1134 NtClose(DosRecord->ServerEvent);
1135
1136 /* Remove the DOS entry */
1137 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1138 RemoveEntryList(&DosRecord->Entry);
1139 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1140 }
1141
1142 if (ConsoleRecord->CurrentDirs != NULL)
1143 {
1144 /* Free the current directories */
1145 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
1146 ConsoleRecord->CurrentDirs = NULL;
1147 ConsoleRecord->CurDirsLength = 0;
1148 }
1149
1150 /* Close the event handle */
1151 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
1152
1153 /* Remove the console record */
1154 RemoveEntryList(&ConsoleRecord->Entry);
1155 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
1156 }
1157 else
1158 {
1159 // TODO: NOT IMPLEMENTED
1160 UNIMPLEMENTED;
1161 Status = STATUS_NOT_IMPLEMENTED;
1162 }
1163
1164 Cleanup:
1165 /* Leave the critical section */
1166 RtlLeaveCriticalSection(CriticalSection);
1167
1168 return Status;
1169 }
1170
1171 CSR_API(BaseSrvIsFirstVDM)
1172 {
1173 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
1174
1175 /* Return the result */
1176 IsFirstVDMRequest->FirstVDM = FirstVDM;
1177
1178 /* Clear the first VDM flag */
1179 FirstVDM = FALSE;
1180
1181 return STATUS_SUCCESS;
1182 }
1183
1184 CSR_API(BaseSrvGetVDMExitCode)
1185 {
1186 NTSTATUS Status;
1187 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
1188 PLIST_ENTRY i = NULL;
1189 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1190 PVDM_DOS_RECORD DosRecord = NULL;
1191
1192 /* Enter the critical section */
1193 RtlEnterCriticalSection(&DosCriticalSection);
1194
1195 /* Get the console record */
1196 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
1197 if (!NT_SUCCESS(Status)) goto Cleanup;
1198
1199 /* Search for a DOS record that has the same parent process handle */
1200 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1201 {
1202 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1203 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
1204 }
1205
1206 /* Check if no DOS record was found */
1207 if (i == &ConsoleRecord->DosListHead)
1208 {
1209 Status = STATUS_NOT_FOUND;
1210 goto Cleanup;
1211 }
1212
1213 /* Check if this task is still running */
1214 if (DosRecord->State != VDM_READY)
1215 {
1216 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
1217 goto Cleanup;
1218 }
1219
1220 /* Return the exit code */
1221 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
1222
1223 /* Since this is a zombie task record, remove it */
1224 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1225 RemoveEntryList(&DosRecord->Entry);
1226 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1227
1228 Cleanup:
1229 /* Leave the critical section */
1230 RtlLeaveCriticalSection(&DosCriticalSection);
1231
1232 return Status;
1233 }
1234
1235 CSR_API(BaseSrvSetReenterCount)
1236 {
1237 NTSTATUS Status = STATUS_SUCCESS;
1238 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
1239 PVDM_CONSOLE_RECORD ConsoleRecord;
1240
1241 /* Enter the critical section */
1242 RtlEnterCriticalSection(&DosCriticalSection);
1243
1244 /* Get the console record */
1245 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
1246 if (!NT_SUCCESS(Status)) goto Cleanup;
1247
1248 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
1249 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
1250 {
1251 ConsoleRecord->ReenterCount--;
1252 if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
1253 }
1254 else Status = STATUS_INVALID_PARAMETER;
1255
1256 Cleanup:
1257 /* Leave the critical section */
1258 RtlLeaveCriticalSection(&DosCriticalSection);
1259
1260 return Status;
1261 }
1262
1263 CSR_API(BaseSrvSetVDMCurDirs)
1264 {
1265 NTSTATUS Status;
1266 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1267 PVDM_CONSOLE_RECORD ConsoleRecord;
1268 PCHAR Buffer = NULL;
1269
1270 /* Validate the input buffer */
1271 if (!CsrValidateMessageBuffer(ApiMessage,
1272 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1273 VDMCurrentDirsRequest->cchCurDirs,
1274 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1275 {
1276 return STATUS_INVALID_PARAMETER;
1277 }
1278
1279 /* Enter the critical section */
1280 RtlEnterCriticalSection(&DosCriticalSection);
1281
1282 /* Find the console record */
1283 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1284 if (!NT_SUCCESS(Status)) goto Cleanup;
1285
1286 if (ConsoleRecord->CurrentDirs == NULL)
1287 {
1288 /* Allocate memory for the current directory information */
1289 Buffer = RtlAllocateHeap(BaseSrvHeap,
1290 HEAP_ZERO_MEMORY,
1291 VDMCurrentDirsRequest->cchCurDirs);
1292 }
1293 else
1294 {
1295 /* Resize the amount of allocated memory */
1296 Buffer = RtlReAllocateHeap(BaseSrvHeap,
1297 HEAP_ZERO_MEMORY,
1298 ConsoleRecord->CurrentDirs,
1299 VDMCurrentDirsRequest->cchCurDirs);
1300 }
1301
1302 if (Buffer == NULL)
1303 {
1304 /* Allocation failed */
1305 Status = STATUS_NO_MEMORY;
1306 goto Cleanup;
1307 }
1308
1309 /* Update the console record */
1310 ConsoleRecord->CurrentDirs = Buffer;
1311 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
1312
1313 /* Copy the data */
1314 RtlMoveMemory(ConsoleRecord->CurrentDirs,
1315 VDMCurrentDirsRequest->lpszzCurDirs,
1316 VDMCurrentDirsRequest->cchCurDirs);
1317
1318 Cleanup:
1319 /* Leave the critical section */
1320 RtlLeaveCriticalSection(&DosCriticalSection);
1321
1322 return Status;
1323 }
1324
1325 CSR_API(BaseSrvGetVDMCurDirs)
1326 {
1327 NTSTATUS Status;
1328 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1329 PVDM_CONSOLE_RECORD ConsoleRecord;
1330
1331 /* Validate the output buffer */
1332 if (!CsrValidateMessageBuffer(ApiMessage,
1333 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1334 VDMCurrentDirsRequest->cchCurDirs,
1335 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1336 {
1337 return STATUS_INVALID_PARAMETER;
1338 }
1339
1340 /* Enter the critical section */
1341 RtlEnterCriticalSection(&DosCriticalSection);
1342
1343 /* Find the console record */
1344 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1345 if (!NT_SUCCESS(Status)) goto Cleanup;
1346
1347 /* Return the actual size of the current directory information */
1348 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
1349
1350 /* Check if the buffer is large enough */
1351 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
1352 {
1353 Status = STATUS_BUFFER_TOO_SMALL;
1354 goto Cleanup;
1355 }
1356
1357 /* Copy the data */
1358 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
1359 ConsoleRecord->CurrentDirs,
1360 ConsoleRecord->CurDirsLength);
1361
1362 Cleanup:
1363 /* Leave the critical section */
1364 RtlLeaveCriticalSection(&DosCriticalSection);
1365
1366 return Status;
1367 }
1368
1369 CSR_API(BaseSrvBatNotification)
1370 {
1371 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1372 return STATUS_NOT_IMPLEMENTED;
1373 }
1374
1375 CSR_API(BaseSrvRegisterWowExec)
1376 {
1377 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1378 return STATUS_NOT_IMPLEMENTED;
1379 }
1380
1381 CSR_API(BaseSrvRefreshIniFileMapping)
1382 {
1383 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1384 return STATUS_NOT_IMPLEMENTED;
1385 }
1386
1387 /* EOF */