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