[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 ULONG NTAPI GetNextDosSesId(VOID)
44 {
45 ULONG SessionId;
46 PLIST_ENTRY i;
47 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
48 BOOLEAN Found;
49
50 /* Search for an available session ID */
51 for (SessionId = 1; SessionId != 0; SessionId++)
52 {
53 Found = FALSE;
54
55 /* Check if the ID is already in use */
56 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
57 {
58 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
59 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
60 }
61
62 /* If not, we found one */
63 if (!Found) break;
64 }
65
66 ASSERT(SessionId != 0);
67
68 /* Return the session ID */
69 return SessionId;
70 }
71
72 BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
73 {
74 NTSTATUS Status;
75 BOOLEAN VdmAllowed = TRUE;
76 HANDLE RootKey, KeyHandle;
77 UNICODE_STRING KeyName, ValueName, MachineKeyName;
78 OBJECT_ATTRIBUTES Attributes;
79 UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
80 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
81 ULONG ActualSize;
82
83 /* Initialize the unicode strings */
84 RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine");
85 RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME);
86 RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME);
87
88 InitializeObjectAttributes(&Attributes,
89 &MachineKeyName,
90 OBJ_CASE_INSENSITIVE,
91 NULL,
92 NULL);
93
94 /* Open the local machine key */
95 Status = NtOpenKey(&RootKey, KEY_READ, &Attributes);
96 if (!NT_SUCCESS(Status)) return FALSE;
97
98 InitializeObjectAttributes(&Attributes,
99 &KeyName,
100 OBJ_CASE_INSENSITIVE,
101 RootKey,
102 NULL);
103
104 /* Open the policy key in the local machine hive, if it exists */
105 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
106 {
107 /* Read the value, if it's set */
108 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
109 &ValueName,
110 KeyValuePartialInformation,
111 ValueInfo,
112 sizeof(ValueBuffer),
113 &ActualSize)))
114 {
115 if (*((PULONG)ValueInfo->Data))
116 {
117 /* The VDM has been disabled in the registry */
118 VdmAllowed = FALSE;
119 }
120 }
121
122 NtClose(KeyHandle);
123 }
124
125 /* Close the local machine key */
126 NtClose(RootKey);
127
128 /* If it's disabled system-wide, there's no need to check the user key */
129 if (!VdmAllowed) return FALSE;
130
131 /* Open the current user key of the client */
132 if (!CsrImpersonateClient(NULL)) return VdmAllowed;
133 Status = RtlOpenCurrentUser(KEY_READ, &RootKey);
134 CsrRevertToSelf();
135
136 /* If that fails, return the system-wide setting */
137 if (!NT_SUCCESS(Status)) return VdmAllowed;
138
139 InitializeObjectAttributes(&Attributes,
140 &KeyName,
141 OBJ_CASE_INSENSITIVE,
142 RootKey,
143 NULL);
144
145 /* Open the policy key in the current user hive, if it exists */
146 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
147 {
148 /* Read the value, if it's set */
149 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
150 &ValueName,
151 KeyValuePartialInformation,
152 ValueInfo,
153 sizeof(ValueBuffer),
154 &ActualSize)))
155 {
156 if (*((PULONG)ValueInfo->Data))
157 {
158 /* The VDM has been disabled in the registry */
159 VdmAllowed = FALSE;
160 }
161 }
162
163 NtClose(KeyHandle);
164 }
165
166 return VdmAllowed;
167 }
168
169 NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
170 {
171 NTSTATUS Status;
172
173 /* Create the event */
174 Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
175 if (!NT_SUCCESS(Status)) return Status;
176
177 /* Duplicate the event into the client process */
178 Status = NtDuplicateObject(NtCurrentProcess(),
179 *ServerEvent,
180 CsrGetClientThread()->Process->ProcessHandle,
181 ClientEvent,
182 0,
183 0,
184 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
185
186 if (!NT_SUCCESS(Status)) NtClose(*ServerEvent);
187 return Status;
188 }
189
190 VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
191 {
192 /* Free the allocated structure members */
193 if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
194 if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName);
195 if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile);
196 if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory);
197 if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env);
198 if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop);
199 if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title);
200 if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved);
201
202 /* Free the structure itself */
203 RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
204 }
205
206 BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
207 {
208 BOOLEAN Success = FALSE;
209 PVDM_COMMAND_INFO CommandInfo = NULL;
210
211 /* Allocate the command information structure */
212 CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap,
213 HEAP_ZERO_MEMORY,
214 sizeof(VDM_COMMAND_INFO));
215 if (CommandInfo == NULL) return FALSE;
216
217 /* Fill the structure */
218 CommandInfo->TaskId = CheckVdmRequest->iTask;
219 CommandInfo->ExitCode = DosRecord->ExitCode;
220 CommandInfo->CodePage = CheckVdmRequest->CodePage;
221 CommandInfo->StdIn = CheckVdmRequest->StdIn;
222 CommandInfo->StdOut = CheckVdmRequest->StdOut;
223 CommandInfo->StdErr = CheckVdmRequest->StdErr;
224
225 /* Allocate memory for the command line */
226 CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap,
227 HEAP_ZERO_MEMORY,
228 CheckVdmRequest->CmdLen);
229 if (CommandInfo->CmdLine == NULL) goto Cleanup;
230
231 /* Copy the command line */
232 RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen);
233
234 /* Allocate memory for the application name */
235 CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap,
236 HEAP_ZERO_MEMORY,
237 CheckVdmRequest->AppLen);
238 if (CommandInfo->AppName == NULL) goto Cleanup;
239
240 /* Copy the application name */
241 RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen);
242
243 /* Allocate memory for the PIF file name */
244 if (CheckVdmRequest->PifLen != 0)
245 {
246 CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap,
247 HEAP_ZERO_MEMORY,
248 CheckVdmRequest->PifLen);
249 if (CommandInfo->PifFile == NULL) goto Cleanup;
250
251 /* Copy the PIF file name */
252 RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen);
253 }
254 else CommandInfo->PifFile = NULL;
255
256 /* Allocate memory for the current directory */
257 if (CheckVdmRequest->CurDirectoryLen != 0)
258 {
259 CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap,
260 HEAP_ZERO_MEMORY,
261 CheckVdmRequest->CurDirectoryLen);
262 if (CommandInfo->CurDirectory == NULL) goto Cleanup;
263
264 /* Copy the current directory */
265 RtlMoveMemory(CommandInfo->CurDirectory,
266 CheckVdmRequest->CurDirectory,
267 CheckVdmRequest->CurDirectoryLen);
268 }
269 else CommandInfo->CurDirectory = NULL;
270
271 /* Allocate memory for the environment block */
272 CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap,
273 HEAP_ZERO_MEMORY,
274 CheckVdmRequest->EnvLen);
275 if (CommandInfo->Env == NULL) goto Cleanup;
276
277 /* Copy the environment block */
278 RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen);
279
280 CommandInfo->EnvLen = CheckVdmRequest->EnvLen;
281 RtlMoveMemory(&CommandInfo->StartupInfo,
282 CheckVdmRequest->StartupInfo,
283 sizeof(STARTUPINFOA));
284
285 /* Allocate memory for the desktop */
286 if (CheckVdmRequest->DesktopLen != 0)
287 {
288 CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap,
289 HEAP_ZERO_MEMORY,
290 CheckVdmRequest->DesktopLen);
291 if (CommandInfo->Desktop == NULL) goto Cleanup;
292
293 /* Copy the desktop name */
294 RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen);
295 }
296 else CommandInfo->Desktop = NULL;
297
298 CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen;
299
300 /* Allocate memory for the title */
301 if (CheckVdmRequest->TitleLen != 0)
302 {
303 CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap,
304 HEAP_ZERO_MEMORY,
305 CheckVdmRequest->TitleLen);
306 if (CommandInfo->Title == NULL) goto Cleanup;
307
308 /* Copy the title */
309 RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen);
310 }
311 else CommandInfo->Title = NULL;
312
313 CommandInfo->TitleLen = CheckVdmRequest->TitleLen;
314
315 /* Allocate memory for the reserved field */
316 if (CheckVdmRequest->ReservedLen != 0)
317 {
318 CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap,
319 HEAP_ZERO_MEMORY,
320 CheckVdmRequest->ReservedLen);
321 if (CommandInfo->Reserved == NULL) goto Cleanup;
322
323 /* Copy the reserved field */
324 RtlMoveMemory(CommandInfo->Reserved,
325 CheckVdmRequest->Reserved,
326 CheckVdmRequest->ReservedLen);
327 }
328 else CommandInfo->Reserved = NULL;
329
330 CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen;
331
332 CommandInfo->CmdLen = CheckVdmRequest->CmdLen;
333 CommandInfo->AppLen = CheckVdmRequest->AppLen;
334 CommandInfo->PifLen = CheckVdmRequest->PifLen;
335 CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen;
336 CommandInfo->VDMState = DosRecord->State;
337 // TODO: Set CommandInfo->CurrentDrive
338 // TODO: Set CommandInfo->ComingFromBat
339
340 /* Set the DOS record's command structure */
341 DosRecord->CommandInfo = CommandInfo;
342
343 /* The operation was successful */
344 Success = TRUE;
345
346 Cleanup:
347 /* If it wasn't successful, free the memory */
348 if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
349
350 return Success;
351 }
352
353 VOID NTAPI BaseInitializeVDM(VOID)
354 {
355 /* Initialize the list head */
356 InitializeListHead(&VDMConsoleListHead);
357
358 /* Initialize the critical section */
359 RtlInitializeCriticalSection(&DosCriticalSection);
360 RtlInitializeCriticalSection(&WowCriticalSection);
361 }
362
363 /* PUBLIC SERVER APIS *********************************************************/
364
365 CSR_API(BaseSrvCheckVDM)
366 {
367 NTSTATUS Status;
368 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
369 PRTL_CRITICAL_SECTION CriticalSection = NULL;
370 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
371 PVDM_DOS_RECORD DosRecord = NULL;
372 BOOLEAN NewConsoleRecord = FALSE;
373
374 /* Don't do anything if the VDM has been disabled in the registry */
375 if (!BaseSrvIsVdmAllowed()) return STATUS_ACCESS_DENIED;
376
377 /* Validate the message buffers */
378 if (!CsrValidateMessageBuffer(ApiMessage,
379 (PVOID*)&CheckVdmRequest->CmdLine,
380 CheckVdmRequest->CmdLen,
381 sizeof(*CheckVdmRequest->CmdLine))
382 || !CsrValidateMessageBuffer(ApiMessage,
383 (PVOID*)&CheckVdmRequest->AppName,
384 CheckVdmRequest->AppLen,
385 sizeof(*CheckVdmRequest->AppName))
386 || !CsrValidateMessageBuffer(ApiMessage,
387 (PVOID*)&CheckVdmRequest->PifFile,
388 CheckVdmRequest->PifLen,
389 sizeof(*CheckVdmRequest->PifFile))
390 || !CsrValidateMessageBuffer(ApiMessage,
391 (PVOID*)&CheckVdmRequest->CurDirectory,
392 CheckVdmRequest->CurDirectoryLen,
393 sizeof(*CheckVdmRequest->CurDirectory))
394 || !CsrValidateMessageBuffer(ApiMessage,
395 (PVOID*)&CheckVdmRequest->Desktop,
396 CheckVdmRequest->DesktopLen,
397 sizeof(*CheckVdmRequest->Desktop))
398 || !CsrValidateMessageBuffer(ApiMessage,
399 (PVOID*)&CheckVdmRequest->Title,
400 CheckVdmRequest->TitleLen,
401 sizeof(*CheckVdmRequest->Title))
402 || !CsrValidateMessageBuffer(ApiMessage,
403 (PVOID*)&CheckVdmRequest->Reserved,
404 CheckVdmRequest->ReservedLen,
405 sizeof(*CheckVdmRequest->Reserved)))
406 {
407 return STATUS_INVALID_PARAMETER;
408 }
409
410 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
411 ? &DosCriticalSection
412 : &WowCriticalSection;
413
414 /* Enter the critical section */
415 RtlEnterCriticalSection(CriticalSection);
416
417 /* Check if this is a DOS or WOW VDM */
418 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
419 {
420 /* Get the console record */
421 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
422 &ConsoleRecord);
423
424 if (!NT_SUCCESS(Status))
425 {
426 /* Allocate a new console record */
427 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
428 HEAP_ZERO_MEMORY,
429 sizeof(VDM_CONSOLE_RECORD));
430 if (ConsoleRecord == NULL)
431 {
432 Status = STATUS_NO_MEMORY;
433 goto Cleanup;
434 }
435
436 /* Initialize the console record */
437 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
438 ConsoleRecord->CurrentDirs = NULL;
439 ConsoleRecord->CurDirsLength = 0;
440 ConsoleRecord->SessionId = GetNextDosSesId();
441 InitializeListHead(&ConsoleRecord->DosListHead);
442 // TODO: The console record structure is incomplete
443
444 /* Remember that the console record was allocated here */
445 NewConsoleRecord = TRUE;
446 }
447
448 /* Allocate a new DOS record */
449 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
450 HEAP_ZERO_MEMORY,
451 sizeof(VDM_DOS_RECORD));
452 if (DosRecord == NULL)
453 {
454 Status = STATUS_NO_MEMORY;
455 goto Cleanup;
456 }
457
458 /* Initialize the DOS record */
459 DosRecord->State = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
460 DosRecord->ExitCode = 0;
461 // TODO: The DOS record structure is incomplete
462
463 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
464 if (!NT_SUCCESS(Status)) goto Cleanup;
465
466 /* Translate the input structure into a VDM command structure and set it in the DOS record */
467 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
468 {
469 /* The only possibility is that an allocation failure occurred */
470 Status = STATUS_NO_MEMORY;
471 goto Cleanup;
472 }
473
474 /* Add the DOS record */
475 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
476
477 if (NewConsoleRecord)
478 {
479 /* Add the console record */
480 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
481 }
482
483 CheckVdmRequest->VDMState = DosRecord->State;
484 Status = STATUS_SUCCESS;
485 }
486 else
487 {
488 // TODO: NOT IMPLEMENTED
489 UNIMPLEMENTED;
490 return STATUS_NOT_IMPLEMENTED;
491 }
492
493 Cleanup:
494 /* Check if it failed */
495 if (!NT_SUCCESS(Status))
496 {
497 /* Free the DOS record */
498 if (DosRecord != NULL)
499 {
500 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
501 DosRecord = NULL;
502 }
503
504 /* Free the console record if it was allocated here */
505 if (NewConsoleRecord)
506 {
507 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
508 ConsoleRecord = NULL;
509 }
510 }
511
512 /* Leave the critical section */
513 RtlLeaveCriticalSection(CriticalSection);
514
515 return Status;
516 }
517
518 CSR_API(BaseSrvUpdateVDMEntry)
519 {
520 DPRINT1("%s not yet implemented\n", __FUNCTION__);
521 return STATUS_NOT_IMPLEMENTED;
522 }
523
524 CSR_API(BaseSrvGetNextVDMCommand)
525 {
526 DPRINT1("%s not yet implemented\n", __FUNCTION__);
527 return STATUS_NOT_IMPLEMENTED;
528 }
529
530 CSR_API(BaseSrvExitVDM)
531 {
532 NTSTATUS Status;
533 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
534 PRTL_CRITICAL_SECTION CriticalSection = NULL;
535 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
536 PVDM_DOS_RECORD DosRecord;
537
538 CriticalSection = (ExitVdmRequest->iWowTask == 0)
539 ? &DosCriticalSection
540 : &WowCriticalSection;
541
542 /* Enter the critical section */
543 RtlEnterCriticalSection(CriticalSection);
544
545 if (ExitVdmRequest->iWowTask == 0)
546 {
547 /* Get the console record */
548 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
549 if (!NT_SUCCESS(Status)) goto Cleanup;
550
551 /* Cleanup the DOS records */
552 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
553 {
554 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
555 VDM_DOS_RECORD,
556 Entry);
557
558 /* Remove the DOS entry */
559 RemoveEntryList(&DosRecord->Entry);
560 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
561 }
562
563 if (ConsoleRecord->CurrentDirs != NULL)
564 {
565 /* Free the current directories */
566 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
567 ConsoleRecord->CurrentDirs = NULL;
568 ConsoleRecord->CurDirsLength = 0;
569 }
570
571 /* Remove the console record */
572 RemoveEntryList(&ConsoleRecord->Entry);
573 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
574 }
575 else
576 {
577 // TODO: NOT IMPLEMENTED
578 UNIMPLEMENTED;
579 return STATUS_NOT_IMPLEMENTED;
580 }
581
582 Cleanup:
583 /* Leave the critical section */
584 RtlLeaveCriticalSection(CriticalSection);
585
586 return Status;
587 }
588
589 CSR_API(BaseSrvIsFirstVDM)
590 {
591 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
592
593 /* Return the result */
594 IsFirstVDMRequest->FirstVDM = FirstVDM;
595
596 /* Clear the first VDM flag */
597 FirstVDM = FALSE;
598
599 return STATUS_SUCCESS;
600 }
601
602 CSR_API(BaseSrvGetVDMExitCode)
603 {
604 NTSTATUS Status;
605 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
606 PLIST_ENTRY i = NULL;
607 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
608 PVDM_DOS_RECORD DosRecord = NULL;
609
610 /* Enter the critical section */
611 RtlEnterCriticalSection(&DosCriticalSection);
612
613 /* Get the console record */
614 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
615 if (!NT_SUCCESS(Status)) goto Cleanup;
616
617 /* Search for a DOS record that has the same parent process handle */
618 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
619 {
620 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
621 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
622 }
623
624 /* Check if no DOS record was found */
625 if (i == &ConsoleRecord->DosListHead)
626 {
627 Status = STATUS_NOT_FOUND;
628 goto Cleanup;
629 }
630
631 /* Check if this task is still running */
632 if (DosRecord->State == VDM_READY)
633 {
634 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
635 goto Cleanup;
636 }
637
638 /* Return the exit code */
639 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
640
641 /* Since this is a zombie task record, remove it */
642 RemoveEntryList(&DosRecord->Entry);
643 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
644
645 Cleanup:
646 /* Leave the critical section */
647 RtlLeaveCriticalSection(&DosCriticalSection);
648
649 return Status;
650 }
651
652 CSR_API(BaseSrvSetReenterCount)
653 {
654 DPRINT1("%s not yet implemented\n", __FUNCTION__);
655 return STATUS_NOT_IMPLEMENTED;
656 }
657
658 CSR_API(BaseSrvSetVDMCurDirs)
659 {
660 NTSTATUS Status;
661 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
662 PVDM_CONSOLE_RECORD ConsoleRecord;
663 PCHAR Buffer = NULL;
664
665 /* Validate the input buffer */
666 if (!CsrValidateMessageBuffer(ApiMessage,
667 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
668 VDMCurrentDirsRequest->cchCurDirs,
669 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
670 {
671 return STATUS_INVALID_PARAMETER;
672 }
673
674 /* Enter the critical section */
675 RtlEnterCriticalSection(&DosCriticalSection);
676
677 /* Find the console record */
678 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
679 if (!NT_SUCCESS(Status)) goto Cleanup;
680
681 if (ConsoleRecord->CurrentDirs == NULL)
682 {
683 /* Allocate memory for the current directory information */
684 Buffer = RtlAllocateHeap(BaseSrvHeap,
685 HEAP_ZERO_MEMORY,
686 VDMCurrentDirsRequest->cchCurDirs);
687 }
688 else
689 {
690 /* Resize the amount of allocated memory */
691 Buffer = RtlReAllocateHeap(BaseSrvHeap,
692 HEAP_ZERO_MEMORY,
693 ConsoleRecord->CurrentDirs,
694 VDMCurrentDirsRequest->cchCurDirs);
695 }
696
697 if (Buffer == NULL)
698 {
699 /* Allocation failed */
700 Status = STATUS_NO_MEMORY;
701 goto Cleanup;
702 }
703
704 /* Update the console record */
705 ConsoleRecord->CurrentDirs = Buffer;
706 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
707
708 /* Copy the data */
709 RtlMoveMemory(ConsoleRecord->CurrentDirs,
710 VDMCurrentDirsRequest->lpszzCurDirs,
711 VDMCurrentDirsRequest->cchCurDirs);
712
713 Cleanup:
714 /* Leave the critical section */
715 RtlLeaveCriticalSection(&DosCriticalSection);
716
717 return Status;
718 }
719
720 CSR_API(BaseSrvGetVDMCurDirs)
721 {
722 NTSTATUS Status;
723 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
724 PVDM_CONSOLE_RECORD ConsoleRecord;
725
726 /* Validate the output buffer */
727 if (!CsrValidateMessageBuffer(ApiMessage,
728 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
729 VDMCurrentDirsRequest->cchCurDirs,
730 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
731 {
732 return STATUS_INVALID_PARAMETER;
733 }
734
735 /* Enter the critical section */
736 RtlEnterCriticalSection(&DosCriticalSection);
737
738 /* Find the console record */
739 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
740 if (!NT_SUCCESS(Status)) goto Cleanup;
741
742 /* Return the actual size of the current directory information */
743 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
744
745 /* Check if the buffer is large enough */
746 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
747 {
748 Status = STATUS_BUFFER_TOO_SMALL;
749 goto Cleanup;
750 }
751
752 /* Copy the data */
753 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
754 ConsoleRecord->CurrentDirs,
755 ConsoleRecord->CurDirsLength);
756
757 Cleanup:
758 /* Leave the critical section */
759 RtlLeaveCriticalSection(&DosCriticalSection);
760
761 return Status;
762 }
763
764 CSR_API(BaseSrvBatNotification)
765 {
766 DPRINT1("%s not yet implemented\n", __FUNCTION__);
767 return STATUS_NOT_IMPLEMENTED;
768 }
769
770 CSR_API(BaseSrvRegisterWowExec)
771 {
772 DPRINT1("%s not yet implemented\n", __FUNCTION__);
773 return STATUS_NOT_IMPLEMENTED;
774 }
775
776 CSR_API(BaseSrvRefreshIniFileMapping)
777 {
778 DPRINT1("%s not yet implemented\n", __FUNCTION__);
779 return STATUS_NOT_IMPLEMENTED;
780 }
781
782 /* EOF */