674f91cd7d1c4b16980c2185d1ae46ecca2c7bde
[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 // HACK: I'm not sure if this should happen...
854 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
855 {
856 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
857 if (DosRecord->State == VDM_NOT_READY)
858 {
859 /* If NTVDM is asking for a new command, it means these are done */
860 DosRecord->State = VDM_READY;
861
862 NtSetEvent(DosRecord->ServerEvent, NULL);
863 NtClose(DosRecord->ServerEvent);
864 DosRecord->ServerEvent = NULL;
865 }
866 }
867
868 /* Search for a DOS record that isn't loaded yet */
869 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
870 {
871 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
872 if (DosRecord->State == VDM_NOT_LOADED) break;
873 }
874
875 if (i != &ConsoleRecord->DosListHead)
876 {
877 /* Fill the command information */
878 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
879 if (!NT_SUCCESS(Status)) goto Cleanup;
880
881 /* Free the command information, it's no longer needed */
882 BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
883 DosRecord->CommandInfo = NULL;
884
885 /* Update the VDM state */
886 DosRecord->State = VDM_NOT_READY;
887
888 Status = STATUS_SUCCESS;
889 goto Cleanup;
890 }
891 }
892 else
893 {
894 // TODO: WOW SUPPORT NOT IMPLEMENTED
895 Status = STATUS_NOT_IMPLEMENTED;
896 goto Cleanup;
897 }
898
899 /* There is no command yet */
900 if (ConsoleRecord->ServerEvent)
901 {
902 /* Reset the event */
903 NtResetEvent(ConsoleRecord->ServerEvent, NULL);
904 }
905 else
906 {
907 /* Create a pair of wait handles */
908 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
909 &ConsoleRecord->ClientEvent);
910 if (!NT_SUCCESS(Status)) goto Cleanup;
911 }
912
913 /* Return the client event handle */
914 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
915
916 Cleanup:
917 /* Leave the critical section */
918 RtlLeaveCriticalSection(CriticalSection);
919
920 return Status;
921 }
922
923 CSR_API(BaseSrvExitVDM)
924 {
925 NTSTATUS Status;
926 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
927 PRTL_CRITICAL_SECTION CriticalSection = NULL;
928 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
929 PVDM_DOS_RECORD DosRecord;
930
931 CriticalSection = (ExitVdmRequest->iWowTask == 0)
932 ? &DosCriticalSection
933 : &WowCriticalSection;
934
935 /* Enter the critical section */
936 RtlEnterCriticalSection(CriticalSection);
937
938 if (ExitVdmRequest->iWowTask == 0)
939 {
940 /* Get the console record */
941 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
942 if (!NT_SUCCESS(Status)) goto Cleanup;
943
944 /* Cleanup the DOS records */
945 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
946 {
947 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
948 VDM_DOS_RECORD,
949 Entry);
950
951 /* Set the event and close it */
952 NtSetEvent(DosRecord->ServerEvent, NULL);
953 NtClose(DosRecord->ServerEvent);
954
955 /* Remove the DOS entry */
956 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
957 RemoveEntryList(&DosRecord->Entry);
958 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
959 }
960
961 if (ConsoleRecord->CurrentDirs != NULL)
962 {
963 /* Free the current directories */
964 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
965 ConsoleRecord->CurrentDirs = NULL;
966 ConsoleRecord->CurDirsLength = 0;
967 }
968
969 /* Close the event handle */
970 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
971
972 /* Remove the console record */
973 RemoveEntryList(&ConsoleRecord->Entry);
974 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
975 }
976 else
977 {
978 // TODO: NOT IMPLEMENTED
979 UNIMPLEMENTED;
980 Status = STATUS_NOT_IMPLEMENTED;
981 }
982
983 Cleanup:
984 /* Leave the critical section */
985 RtlLeaveCriticalSection(CriticalSection);
986
987 return Status;
988 }
989
990 CSR_API(BaseSrvIsFirstVDM)
991 {
992 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
993
994 /* Return the result */
995 IsFirstVDMRequest->FirstVDM = FirstVDM;
996
997 /* Clear the first VDM flag */
998 FirstVDM = FALSE;
999
1000 return STATUS_SUCCESS;
1001 }
1002
1003 CSR_API(BaseSrvGetVDMExitCode)
1004 {
1005 NTSTATUS Status;
1006 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
1007 PLIST_ENTRY i = NULL;
1008 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1009 PVDM_DOS_RECORD DosRecord = NULL;
1010
1011 /* Enter the critical section */
1012 RtlEnterCriticalSection(&DosCriticalSection);
1013
1014 /* Get the console record */
1015 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
1016 if (!NT_SUCCESS(Status)) goto Cleanup;
1017
1018 /* Search for a DOS record that has the same parent process handle */
1019 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1020 {
1021 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1022 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
1023 }
1024
1025 /* Check if no DOS record was found */
1026 if (i == &ConsoleRecord->DosListHead)
1027 {
1028 Status = STATUS_NOT_FOUND;
1029 goto Cleanup;
1030 }
1031
1032 /* Check if this task is still running */
1033 if (DosRecord->State == VDM_READY)
1034 {
1035 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
1036 goto Cleanup;
1037 }
1038
1039 /* Return the exit code */
1040 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
1041
1042 /* Since this is a zombie task record, remove it */
1043 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1044 RemoveEntryList(&DosRecord->Entry);
1045 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1046
1047 Cleanup:
1048 /* Leave the critical section */
1049 RtlLeaveCriticalSection(&DosCriticalSection);
1050
1051 return Status;
1052 }
1053
1054 CSR_API(BaseSrvSetReenterCount)
1055 {
1056 NTSTATUS Status = STATUS_SUCCESS;
1057 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
1058 PVDM_CONSOLE_RECORD ConsoleRecord;
1059
1060 /* Enter the critical section */
1061 RtlEnterCriticalSection(&DosCriticalSection);
1062
1063 /* Get the console record */
1064 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
1065 if (!NT_SUCCESS(Status)) goto Cleanup;
1066
1067 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
1068 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
1069 {
1070 ConsoleRecord->ReenterCount--;
1071 if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
1072 }
1073 else Status = STATUS_INVALID_PARAMETER;
1074
1075 Cleanup:
1076 /* Leave the critical section */
1077 RtlLeaveCriticalSection(&DosCriticalSection);
1078
1079 return Status;
1080 }
1081
1082 CSR_API(BaseSrvSetVDMCurDirs)
1083 {
1084 NTSTATUS Status;
1085 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1086 PVDM_CONSOLE_RECORD ConsoleRecord;
1087 PCHAR Buffer = NULL;
1088
1089 /* Validate the input buffer */
1090 if (!CsrValidateMessageBuffer(ApiMessage,
1091 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1092 VDMCurrentDirsRequest->cchCurDirs,
1093 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1094 {
1095 return STATUS_INVALID_PARAMETER;
1096 }
1097
1098 /* Enter the critical section */
1099 RtlEnterCriticalSection(&DosCriticalSection);
1100
1101 /* Find the console record */
1102 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1103 if (!NT_SUCCESS(Status)) goto Cleanup;
1104
1105 if (ConsoleRecord->CurrentDirs == NULL)
1106 {
1107 /* Allocate memory for the current directory information */
1108 Buffer = RtlAllocateHeap(BaseSrvHeap,
1109 HEAP_ZERO_MEMORY,
1110 VDMCurrentDirsRequest->cchCurDirs);
1111 }
1112 else
1113 {
1114 /* Resize the amount of allocated memory */
1115 Buffer = RtlReAllocateHeap(BaseSrvHeap,
1116 HEAP_ZERO_MEMORY,
1117 ConsoleRecord->CurrentDirs,
1118 VDMCurrentDirsRequest->cchCurDirs);
1119 }
1120
1121 if (Buffer == NULL)
1122 {
1123 /* Allocation failed */
1124 Status = STATUS_NO_MEMORY;
1125 goto Cleanup;
1126 }
1127
1128 /* Update the console record */
1129 ConsoleRecord->CurrentDirs = Buffer;
1130 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
1131
1132 /* Copy the data */
1133 RtlMoveMemory(ConsoleRecord->CurrentDirs,
1134 VDMCurrentDirsRequest->lpszzCurDirs,
1135 VDMCurrentDirsRequest->cchCurDirs);
1136
1137 Cleanup:
1138 /* Leave the critical section */
1139 RtlLeaveCriticalSection(&DosCriticalSection);
1140
1141 return Status;
1142 }
1143
1144 CSR_API(BaseSrvGetVDMCurDirs)
1145 {
1146 NTSTATUS Status;
1147 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1148 PVDM_CONSOLE_RECORD ConsoleRecord;
1149
1150 /* Validate the output buffer */
1151 if (!CsrValidateMessageBuffer(ApiMessage,
1152 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1153 VDMCurrentDirsRequest->cchCurDirs,
1154 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1155 {
1156 return STATUS_INVALID_PARAMETER;
1157 }
1158
1159 /* Enter the critical section */
1160 RtlEnterCriticalSection(&DosCriticalSection);
1161
1162 /* Find the console record */
1163 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1164 if (!NT_SUCCESS(Status)) goto Cleanup;
1165
1166 /* Return the actual size of the current directory information */
1167 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
1168
1169 /* Check if the buffer is large enough */
1170 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
1171 {
1172 Status = STATUS_BUFFER_TOO_SMALL;
1173 goto Cleanup;
1174 }
1175
1176 /* Copy the data */
1177 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
1178 ConsoleRecord->CurrentDirs,
1179 ConsoleRecord->CurDirsLength);
1180
1181 Cleanup:
1182 /* Leave the critical section */
1183 RtlLeaveCriticalSection(&DosCriticalSection);
1184
1185 return Status;
1186 }
1187
1188 CSR_API(BaseSrvBatNotification)
1189 {
1190 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1191 return STATUS_NOT_IMPLEMENTED;
1192 }
1193
1194 CSR_API(BaseSrvRegisterWowExec)
1195 {
1196 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1197 return STATUS_NOT_IMPLEMENTED;
1198 }
1199
1200 CSR_API(BaseSrvRefreshIniFileMapping)
1201 {
1202 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1203 return STATUS_NOT_IMPLEMENTED;
1204 }
1205
1206 /* EOF */