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