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