c47f8855063bc865067bc8d5073c16018d79f2d9
[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 Cleanup:
344 /* If it wasn't successful, free the memory */
345 if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
346
347 return Success;
348 }
349
350 VOID NTAPI BaseInitializeVDM(VOID)
351 {
352 /* Initialize the list head */
353 InitializeListHead(&VDMConsoleListHead);
354
355 /* Initialize the critical section */
356 RtlInitializeCriticalSection(&DosCriticalSection);
357 RtlInitializeCriticalSection(&WowCriticalSection);
358 }
359
360 /* PUBLIC SERVER APIS *********************************************************/
361
362 CSR_API(BaseSrvCheckVDM)
363 {
364 NTSTATUS Status;
365 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
366 PRTL_CRITICAL_SECTION CriticalSection = NULL;
367 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
368 PVDM_DOS_RECORD DosRecord = NULL;
369 BOOLEAN NewConsoleRecord = FALSE;
370
371 /* Don't do anything if the VDM has been disabled in the registry */
372 if (!BaseSrvIsVdmAllowed()) return STATUS_ACCESS_DENIED;
373
374 /* Validate the message buffers */
375 if (!CsrValidateMessageBuffer(ApiMessage,
376 (PVOID*)&CheckVdmRequest->CmdLine,
377 CheckVdmRequest->CmdLen,
378 sizeof(*CheckVdmRequest->CmdLine))
379 || !CsrValidateMessageBuffer(ApiMessage,
380 (PVOID*)&CheckVdmRequest->AppName,
381 CheckVdmRequest->AppLen,
382 sizeof(*CheckVdmRequest->AppName))
383 || !CsrValidateMessageBuffer(ApiMessage,
384 (PVOID*)&CheckVdmRequest->PifFile,
385 CheckVdmRequest->PifLen,
386 sizeof(*CheckVdmRequest->PifFile))
387 || !CsrValidateMessageBuffer(ApiMessage,
388 (PVOID*)&CheckVdmRequest->CurDirectory,
389 CheckVdmRequest->CurDirectoryLen,
390 sizeof(*CheckVdmRequest->CurDirectory))
391 || !CsrValidateMessageBuffer(ApiMessage,
392 (PVOID*)&CheckVdmRequest->Desktop,
393 CheckVdmRequest->DesktopLen,
394 sizeof(*CheckVdmRequest->Desktop))
395 || !CsrValidateMessageBuffer(ApiMessage,
396 (PVOID*)&CheckVdmRequest->Title,
397 CheckVdmRequest->TitleLen,
398 sizeof(*CheckVdmRequest->Title))
399 || !CsrValidateMessageBuffer(ApiMessage,
400 (PVOID*)&CheckVdmRequest->Reserved,
401 CheckVdmRequest->ReservedLen,
402 sizeof(*CheckVdmRequest->Reserved)))
403 {
404 return STATUS_INVALID_PARAMETER;
405 }
406
407 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
408 ? &DosCriticalSection
409 : &WowCriticalSection;
410
411 /* Enter the critical section */
412 RtlEnterCriticalSection(CriticalSection);
413
414 /* Check if this is a DOS or WOW VDM */
415 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
416 {
417 /* Get the console record */
418 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
419 &ConsoleRecord);
420
421 if (!NT_SUCCESS(Status))
422 {
423 /* Allocate a new console record */
424 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
425 HEAP_ZERO_MEMORY,
426 sizeof(VDM_CONSOLE_RECORD));
427 if (ConsoleRecord == NULL)
428 {
429 Status = STATUS_NO_MEMORY;
430 goto Cleanup;
431 }
432
433 /* Initialize the console record */
434 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
435 ConsoleRecord->CurrentDirs = NULL;
436 ConsoleRecord->CurDirsLength = 0;
437 ConsoleRecord->SessionId = GetNextDosSesId();
438 InitializeListHead(&ConsoleRecord->DosListHead);
439 // TODO: The console record structure is incomplete
440
441 /* Remember that the console record was allocated here */
442 NewConsoleRecord = TRUE;
443 }
444
445 /* Allocate a new DOS record */
446 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
447 HEAP_ZERO_MEMORY,
448 sizeof(VDM_DOS_RECORD));
449 if (DosRecord == NULL)
450 {
451 Status = STATUS_NO_MEMORY;
452 goto Cleanup;
453 }
454
455 /* Initialize the DOS record */
456 DosRecord->State = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
457 DosRecord->ExitCode = 0;
458 // TODO: The DOS record structure is incomplete
459
460 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
461 if (!NT_SUCCESS(Status)) goto Cleanup;
462
463 /* Translate the input structure into a VDM command structure and set it in the DOS record */
464 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
465 {
466 /* The only possibility is that an allocation failure occurred */
467 Status = STATUS_NO_MEMORY;
468 goto Cleanup;
469 }
470
471 /* Add the DOS record */
472 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
473
474 if (NewConsoleRecord)
475 {
476 /* Add the console record */
477 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
478 }
479
480 CheckVdmRequest->VDMState = DosRecord->State;
481 Status = STATUS_SUCCESS;
482 }
483 else
484 {
485 // TODO: NOT IMPLEMENTED
486 UNIMPLEMENTED;
487 return STATUS_NOT_IMPLEMENTED;
488 }
489
490 Cleanup:
491 /* Check if it failed */
492 if (!NT_SUCCESS(Status))
493 {
494 /* Free the DOS record */
495 if (DosRecord != NULL)
496 {
497 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
498 DosRecord = NULL;
499 }
500
501 /* Free the console record if it was allocated here */
502 if (NewConsoleRecord)
503 {
504 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
505 ConsoleRecord = NULL;
506 }
507 }
508
509 /* Leave the critical section */
510 RtlLeaveCriticalSection(CriticalSection);
511
512 return Status;
513 }
514
515 CSR_API(BaseSrvUpdateVDMEntry)
516 {
517 DPRINT1("%s not yet implemented\n", __FUNCTION__);
518 return STATUS_NOT_IMPLEMENTED;
519 }
520
521 CSR_API(BaseSrvGetNextVDMCommand)
522 {
523 DPRINT1("%s not yet implemented\n", __FUNCTION__);
524 return STATUS_NOT_IMPLEMENTED;
525 }
526
527 CSR_API(BaseSrvExitVDM)
528 {
529 NTSTATUS Status;
530 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
531 PRTL_CRITICAL_SECTION CriticalSection = NULL;
532 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
533 PVDM_DOS_RECORD DosRecord;
534
535 CriticalSection = (ExitVdmRequest->iWowTask == 0)
536 ? &DosCriticalSection
537 : &WowCriticalSection;
538
539 /* Enter the critical section */
540 RtlEnterCriticalSection(CriticalSection);
541
542 if (ExitVdmRequest->iWowTask == 0)
543 {
544 /* Get the console record */
545 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
546 if (!NT_SUCCESS(Status)) goto Cleanup;
547
548 /* Cleanup the DOS records */
549 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
550 {
551 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
552 VDM_DOS_RECORD,
553 Entry);
554
555 /* Remove the DOS entry */
556 RemoveEntryList(&DosRecord->Entry);
557 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
558 }
559
560 if (ConsoleRecord->CurrentDirs != NULL)
561 {
562 /* Free the current directories */
563 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
564 ConsoleRecord->CurrentDirs = NULL;
565 ConsoleRecord->CurDirsLength = 0;
566 }
567
568 /* Remove the console record */
569 RemoveEntryList(&ConsoleRecord->Entry);
570 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
571 }
572 else
573 {
574 // TODO: NOT IMPLEMENTED
575 UNIMPLEMENTED;
576 return STATUS_NOT_IMPLEMENTED;
577 }
578
579 Cleanup:
580 /* Leave the critical section */
581 RtlLeaveCriticalSection(CriticalSection);
582
583 return Status;
584 }
585
586 CSR_API(BaseSrvIsFirstVDM)
587 {
588 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
589
590 /* Return the result */
591 IsFirstVDMRequest->FirstVDM = FirstVDM;
592
593 /* Clear the first VDM flag */
594 FirstVDM = FALSE;
595
596 return STATUS_SUCCESS;
597 }
598
599 CSR_API(BaseSrvGetVDMExitCode)
600 {
601 NTSTATUS Status;
602 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
603 PLIST_ENTRY i = NULL;
604 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
605 PVDM_DOS_RECORD DosRecord = NULL;
606
607 /* Enter the critical section */
608 RtlEnterCriticalSection(&DosCriticalSection);
609
610 /* Get the console record */
611 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
612 if (!NT_SUCCESS(Status)) goto Cleanup;
613
614 /* Search for a DOS record that has the same parent process handle */
615 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
616 {
617 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
618 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
619 }
620
621 /* Check if no DOS record was found */
622 if (i == &ConsoleRecord->DosListHead)
623 {
624 Status = STATUS_NOT_FOUND;
625 goto Cleanup;
626 }
627
628 /* Check if this task is still running */
629 if (DosRecord->State == VDM_READY)
630 {
631 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
632 goto Cleanup;
633 }
634
635 /* Return the exit code */
636 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
637
638 /* Since this is a zombie task record, remove it */
639 RemoveEntryList(&DosRecord->Entry);
640 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
641
642 Cleanup:
643 /* Leave the critical section */
644 RtlLeaveCriticalSection(&DosCriticalSection);
645
646 return Status;
647 }
648
649 CSR_API(BaseSrvSetReenterCount)
650 {
651 DPRINT1("%s not yet implemented\n", __FUNCTION__);
652 return STATUS_NOT_IMPLEMENTED;
653 }
654
655 CSR_API(BaseSrvSetVDMCurDirs)
656 {
657 NTSTATUS Status;
658 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
659 PVDM_CONSOLE_RECORD ConsoleRecord;
660 PCHAR Buffer = NULL;
661
662 /* Validate the input buffer */
663 if (!CsrValidateMessageBuffer(ApiMessage,
664 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
665 VDMCurrentDirsRequest->cchCurDirs,
666 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
667 {
668 return STATUS_INVALID_PARAMETER;
669 }
670
671 /* Enter the critical section */
672 RtlEnterCriticalSection(&DosCriticalSection);
673
674 /* Find the console record */
675 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
676 if (!NT_SUCCESS(Status)) goto Cleanup;
677
678 if (ConsoleRecord->CurrentDirs == NULL)
679 {
680 /* Allocate memory for the current directory information */
681 Buffer = RtlAllocateHeap(BaseSrvHeap,
682 HEAP_ZERO_MEMORY,
683 VDMCurrentDirsRequest->cchCurDirs);
684 }
685 else
686 {
687 /* Resize the amount of allocated memory */
688 Buffer = RtlReAllocateHeap(BaseSrvHeap,
689 HEAP_ZERO_MEMORY,
690 ConsoleRecord->CurrentDirs,
691 VDMCurrentDirsRequest->cchCurDirs);
692 }
693
694 if (Buffer == NULL)
695 {
696 /* Allocation failed */
697 Status = STATUS_NO_MEMORY;
698 goto Cleanup;
699 }
700
701 /* Update the console record */
702 ConsoleRecord->CurrentDirs = Buffer;
703 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
704
705 /* Copy the data */
706 RtlMoveMemory(ConsoleRecord->CurrentDirs,
707 VDMCurrentDirsRequest->lpszzCurDirs,
708 VDMCurrentDirsRequest->cchCurDirs);
709
710 Cleanup:
711 /* Leave the critical section */
712 RtlLeaveCriticalSection(&DosCriticalSection);
713
714 return Status;
715 }
716
717 CSR_API(BaseSrvGetVDMCurDirs)
718 {
719 NTSTATUS Status;
720 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
721 PVDM_CONSOLE_RECORD ConsoleRecord;
722
723 /* Validate the output buffer */
724 if (!CsrValidateMessageBuffer(ApiMessage,
725 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
726 VDMCurrentDirsRequest->cchCurDirs,
727 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
728 {
729 return STATUS_INVALID_PARAMETER;
730 }
731
732 /* Enter the critical section */
733 RtlEnterCriticalSection(&DosCriticalSection);
734
735 /* Find the console record */
736 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
737 if (!NT_SUCCESS(Status)) goto Cleanup;
738
739 /* Return the actual size of the current directory information */
740 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
741
742 /* Check if the buffer is large enough */
743 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
744 {
745 Status = STATUS_BUFFER_TOO_SMALL;
746 goto Cleanup;
747 }
748
749 /* Copy the data */
750 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
751 ConsoleRecord->CurrentDirs,
752 ConsoleRecord->CurDirsLength);
753
754 Cleanup:
755 /* Leave the critical section */
756 RtlLeaveCriticalSection(&DosCriticalSection);
757
758 return Status;
759 }
760
761 CSR_API(BaseSrvBatNotification)
762 {
763 DPRINT1("%s not yet implemented\n", __FUNCTION__);
764 return STATUS_NOT_IMPLEMENTED;
765 }
766
767 CSR_API(BaseSrvRegisterWowExec)
768 {
769 DPRINT1("%s not yet implemented\n", __FUNCTION__);
770 return STATUS_NOT_IMPLEMENTED;
771 }
772
773 CSR_API(BaseSrvRefreshIniFileMapping)
774 {
775 DPRINT1("%s not yet implemented\n", __FUNCTION__);
776 return STATUS_NOT_IMPLEMENTED;
777 }
778
779 /* EOF */