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