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