[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 /* Check if nothing was found */
40 if (i == &VDMConsoleListHead) CurrentRecord = NULL;
41
42 *Record = CurrentRecord;
43 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
44 }
45
46 NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
47 {
48 PLIST_ENTRY i;
49 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
50
51 /* Search for a record that has the same console handle */
52 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
53 {
54 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
55 if (CurrentRecord->SessionId == TaskId) break;
56 }
57
58 /* Check if nothing was found */
59 if (i == &VDMConsoleListHead) CurrentRecord = NULL;
60
61 *Record = CurrentRecord;
62 return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
63 }
64
65 ULONG NTAPI GetNextDosSesId(VOID)
66 {
67 ULONG SessionId;
68 PLIST_ENTRY i;
69 PVDM_CONSOLE_RECORD CurrentRecord = NULL;
70 BOOLEAN Found;
71
72 /* Search for an available session ID */
73 for (SessionId = 1; SessionId != 0; SessionId++)
74 {
75 Found = FALSE;
76
77 /* Check if the ID is already in use */
78 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
79 {
80 CurrentRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
81 if (CurrentRecord->SessionId == SessionId) Found = TRUE;
82 }
83
84 /* If not, we found one */
85 if (!Found) break;
86 }
87
88 ASSERT(SessionId != 0);
89
90 /* Return the session ID */
91 return SessionId;
92 }
93
94 BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
95 {
96 NTSTATUS Status;
97 BOOLEAN VdmAllowed = TRUE;
98 HANDLE RootKey, KeyHandle;
99 UNICODE_STRING KeyName, ValueName, MachineKeyName;
100 OBJECT_ATTRIBUTES Attributes;
101 UCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
102 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
103 ULONG ActualSize;
104
105 /* Initialize the unicode strings */
106 RtlInitUnicodeString(&MachineKeyName, L"\\Registry\\Machine");
107 RtlInitUnicodeString(&KeyName, VDM_POLICY_KEY_NAME);
108 RtlInitUnicodeString(&ValueName, VDM_DISALLOWED_VALUE_NAME);
109
110 InitializeObjectAttributes(&Attributes,
111 &MachineKeyName,
112 OBJ_CASE_INSENSITIVE,
113 NULL,
114 NULL);
115
116 /* Open the local machine key */
117 Status = NtOpenKey(&RootKey, KEY_READ, &Attributes);
118 if (!NT_SUCCESS(Status)) return FALSE;
119
120 InitializeObjectAttributes(&Attributes,
121 &KeyName,
122 OBJ_CASE_INSENSITIVE,
123 RootKey,
124 NULL);
125
126 /* Open the policy key in the local machine hive, if it exists */
127 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
128 {
129 /* Read the value, if it's set */
130 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
131 &ValueName,
132 KeyValuePartialInformation,
133 ValueInfo,
134 sizeof(ValueBuffer),
135 &ActualSize)))
136 {
137 if (*((PULONG)ValueInfo->Data))
138 {
139 /* The VDM has been disabled in the registry */
140 VdmAllowed = FALSE;
141 }
142 }
143
144 NtClose(KeyHandle);
145 }
146
147 /* Close the local machine key */
148 NtClose(RootKey);
149
150 /* If it's disabled system-wide, there's no need to check the user key */
151 if (!VdmAllowed) return FALSE;
152
153 /* Open the current user key of the client */
154 if (!CsrImpersonateClient(NULL)) return VdmAllowed;
155 Status = RtlOpenCurrentUser(KEY_READ, &RootKey);
156 CsrRevertToSelf();
157
158 /* If that fails, return the system-wide setting */
159 if (!NT_SUCCESS(Status)) return VdmAllowed;
160
161 InitializeObjectAttributes(&Attributes,
162 &KeyName,
163 OBJ_CASE_INSENSITIVE,
164 RootKey,
165 NULL);
166
167 /* Open the policy key in the current user hive, if it exists */
168 if (NT_SUCCESS(NtOpenKey(&KeyHandle, KEY_READ, &Attributes)))
169 {
170 /* Read the value, if it's set */
171 if (NT_SUCCESS(NtQueryValueKey(KeyHandle,
172 &ValueName,
173 KeyValuePartialInformation,
174 ValueInfo,
175 sizeof(ValueBuffer),
176 &ActualSize)))
177 {
178 if (*((PULONG)ValueInfo->Data))
179 {
180 /* The VDM has been disabled in the registry */
181 VdmAllowed = FALSE;
182 }
183 }
184
185 NtClose(KeyHandle);
186 }
187
188 return VdmAllowed;
189 }
190
191 NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
192 {
193 NTSTATUS Status;
194
195 /* Create the event */
196 Status = NtCreateEvent(ServerEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
197 if (!NT_SUCCESS(Status)) return Status;
198
199 /* Duplicate the event into the client process */
200 Status = NtDuplicateObject(NtCurrentProcess(),
201 *ServerEvent,
202 CsrGetClientThread()->Process->ProcessHandle,
203 ClientEvent,
204 0,
205 0,
206 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
207
208 if (!NT_SUCCESS(Status)) NtClose(*ServerEvent);
209 return Status;
210 }
211
212 VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
213 {
214 /* Free the allocated structure members */
215 if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
216 if (CommandInfo->AppName != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->AppName);
217 if (CommandInfo->PifFile != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->PifFile);
218 if (CommandInfo->CurDirectory != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CurDirectory);
219 if (CommandInfo->Env != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Env);
220 if (CommandInfo->Desktop != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Desktop);
221 if (CommandInfo->Title != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Title);
222 if (CommandInfo->Reserved != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->Reserved);
223
224 /* Free the structure itself */
225 RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
226 }
227
228 VOID NTAPI BaseSrvCleanupVdmRecords(ULONG ProcessId)
229 {
230 PLIST_ENTRY i;
231 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
232 PVDM_DOS_RECORD DosRecord;
233
234 /* Enter the critical section */
235 RtlEnterCriticalSection(&DosCriticalSection);
236
237 /* Search for a record that has the same process handle */
238 for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
239 {
240 ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
241
242 if (ConsoleRecord->ProcessId == ProcessId)
243 {
244 /* Cleanup the DOS records */
245 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
246 {
247 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
248 VDM_DOS_RECORD,
249 Entry);
250
251 /* Set the event and close it */
252 NtSetEvent(DosRecord->ServerEvent, NULL);
253 NtClose(DosRecord->ServerEvent);
254
255 /* Remove the DOS entry */
256 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
257 RemoveEntryList(&DosRecord->Entry);
258 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
259 }
260
261 if (ConsoleRecord->CurrentDirs != NULL)
262 {
263 /* Free the current directories */
264 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
265 ConsoleRecord->CurrentDirs = NULL;
266 ConsoleRecord->CurDirsLength = 0;
267 }
268
269 /* Close the event handle */
270 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
271
272 /* Remove the console record */
273 i = i->Blink;
274 RemoveEntryList(&ConsoleRecord->Entry);
275 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
276 }
277 }
278
279 /* Leave the critical section */
280 RtlLeaveCriticalSection(&DosCriticalSection);
281 }
282
283 BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
284 {
285 BOOLEAN Success = FALSE;
286 PVDM_COMMAND_INFO CommandInfo = NULL;
287
288 /* Allocate the command information structure */
289 CommandInfo = (PVDM_COMMAND_INFO)RtlAllocateHeap(BaseSrvHeap,
290 HEAP_ZERO_MEMORY,
291 sizeof(VDM_COMMAND_INFO));
292 if (CommandInfo == NULL) return FALSE;
293
294 /* Fill the structure */
295 CommandInfo->TaskId = CheckVdmRequest->iTask;
296 CommandInfo->ExitCode = DosRecord->ExitCode;
297 CommandInfo->CodePage = CheckVdmRequest->CodePage;
298 CommandInfo->StdIn = CheckVdmRequest->StdIn;
299 CommandInfo->StdOut = CheckVdmRequest->StdOut;
300 CommandInfo->StdErr = CheckVdmRequest->StdErr;
301
302 /* Allocate memory for the command line */
303 CommandInfo->CmdLine = RtlAllocateHeap(BaseSrvHeap,
304 HEAP_ZERO_MEMORY,
305 CheckVdmRequest->CmdLen);
306 if (CommandInfo->CmdLine == NULL) goto Cleanup;
307
308 /* Copy the command line */
309 RtlMoveMemory(CommandInfo->CmdLine, CheckVdmRequest->CmdLine, CheckVdmRequest->CmdLen);
310
311 /* Allocate memory for the application name */
312 CommandInfo->AppName = RtlAllocateHeap(BaseSrvHeap,
313 HEAP_ZERO_MEMORY,
314 CheckVdmRequest->AppLen);
315 if (CommandInfo->AppName == NULL) goto Cleanup;
316
317 /* Copy the application name */
318 RtlMoveMemory(CommandInfo->AppName, CheckVdmRequest->AppName, CheckVdmRequest->AppLen);
319
320 /* Allocate memory for the PIF file name */
321 if (CheckVdmRequest->PifLen != 0)
322 {
323 CommandInfo->PifFile = RtlAllocateHeap(BaseSrvHeap,
324 HEAP_ZERO_MEMORY,
325 CheckVdmRequest->PifLen);
326 if (CommandInfo->PifFile == NULL) goto Cleanup;
327
328 /* Copy the PIF file name */
329 RtlMoveMemory(CommandInfo->PifFile, CheckVdmRequest->PifFile, CheckVdmRequest->PifLen);
330 }
331 else CommandInfo->PifFile = NULL;
332
333 /* Allocate memory for the current directory */
334 if (CheckVdmRequest->CurDirectoryLen != 0)
335 {
336 CommandInfo->CurDirectory = RtlAllocateHeap(BaseSrvHeap,
337 HEAP_ZERO_MEMORY,
338 CheckVdmRequest->CurDirectoryLen);
339 if (CommandInfo->CurDirectory == NULL) goto Cleanup;
340
341 /* Copy the current directory */
342 RtlMoveMemory(CommandInfo->CurDirectory,
343 CheckVdmRequest->CurDirectory,
344 CheckVdmRequest->CurDirectoryLen);
345 }
346 else CommandInfo->CurDirectory = NULL;
347
348 /* Allocate memory for the environment block */
349 CommandInfo->Env = RtlAllocateHeap(BaseSrvHeap,
350 HEAP_ZERO_MEMORY,
351 CheckVdmRequest->EnvLen);
352 if (CommandInfo->Env == NULL) goto Cleanup;
353
354 /* Copy the environment block */
355 RtlMoveMemory(CommandInfo->Env, CheckVdmRequest->Env, CheckVdmRequest->EnvLen);
356
357 CommandInfo->EnvLen = CheckVdmRequest->EnvLen;
358 RtlMoveMemory(&CommandInfo->StartupInfo,
359 CheckVdmRequest->StartupInfo,
360 sizeof(STARTUPINFOA));
361
362 /* Allocate memory for the desktop */
363 if (CheckVdmRequest->DesktopLen != 0)
364 {
365 CommandInfo->Desktop = RtlAllocateHeap(BaseSrvHeap,
366 HEAP_ZERO_MEMORY,
367 CheckVdmRequest->DesktopLen);
368 if (CommandInfo->Desktop == NULL) goto Cleanup;
369
370 /* Copy the desktop name */
371 RtlMoveMemory(CommandInfo->Desktop, CheckVdmRequest->Desktop, CheckVdmRequest->DesktopLen);
372 }
373 else CommandInfo->Desktop = NULL;
374
375 CommandInfo->DesktopLen = CheckVdmRequest->DesktopLen;
376
377 /* Allocate memory for the title */
378 if (CheckVdmRequest->TitleLen != 0)
379 {
380 CommandInfo->Title = RtlAllocateHeap(BaseSrvHeap,
381 HEAP_ZERO_MEMORY,
382 CheckVdmRequest->TitleLen);
383 if (CommandInfo->Title == NULL) goto Cleanup;
384
385 /* Copy the title */
386 RtlMoveMemory(CommandInfo->Title, CheckVdmRequest->Title, CheckVdmRequest->TitleLen);
387 }
388 else CommandInfo->Title = NULL;
389
390 CommandInfo->TitleLen = CheckVdmRequest->TitleLen;
391
392 /* Allocate memory for the reserved field */
393 if (CheckVdmRequest->ReservedLen != 0)
394 {
395 CommandInfo->Reserved = RtlAllocateHeap(BaseSrvHeap,
396 HEAP_ZERO_MEMORY,
397 CheckVdmRequest->ReservedLen);
398 if (CommandInfo->Reserved == NULL) goto Cleanup;
399
400 /* Copy the reserved field */
401 RtlMoveMemory(CommandInfo->Reserved,
402 CheckVdmRequest->Reserved,
403 CheckVdmRequest->ReservedLen);
404 }
405 else CommandInfo->Reserved = NULL;
406
407 CommandInfo->ReservedLen = CheckVdmRequest->ReservedLen;
408
409 CommandInfo->CmdLen = CheckVdmRequest->CmdLen;
410 CommandInfo->AppLen = CheckVdmRequest->AppLen;
411 CommandInfo->PifLen = CheckVdmRequest->PifLen;
412 CommandInfo->CurDirectoryLen = CheckVdmRequest->CurDirectoryLen;
413 CommandInfo->VDMState = DosRecord->State;
414 // TODO: Set CommandInfo->CurrentDrive
415 // TODO: Set CommandInfo->ComingFromBat
416
417 /* Set the DOS record's command structure */
418 DosRecord->CommandInfo = CommandInfo;
419
420 /* The operation was successful */
421 Success = TRUE;
422
423 Cleanup:
424 /* If it wasn't successful, free the memory */
425 if (!Success) BaseSrvFreeVDMInfo(CommandInfo);
426
427 return Success;
428 }
429
430 NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
431 PBASE_GET_NEXT_VDM_COMMAND Message)
432 {
433 /* Copy the data */
434 Message->iTask = CommandInfo->TaskId;
435 Message->StdIn = CommandInfo->StdIn;
436 Message->StdOut = CommandInfo->StdOut;
437 Message->StdErr = CommandInfo->StdErr;
438 Message->CodePage = CommandInfo->CodePage;
439 Message->dwCreationFlags = CommandInfo->CreationFlags;
440 Message->ExitCode = CommandInfo->ExitCode;
441 Message->CurrentDrive = CommandInfo->CurrentDrive;
442 Message->VDMState = CommandInfo->VDMState;
443 Message->fComingFromBat = CommandInfo->ComingFromBat;
444
445 if (CommandInfo->CmdLen && Message->CmdLen)
446 {
447 if (Message->CmdLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
448
449 /* Copy the command line */
450 RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
451 Message->CmdLen = CommandInfo->CmdLen;
452 }
453
454 if (CommandInfo->AppLen && Message->AppLen)
455 {
456 if (Message->AppLen < CommandInfo->CmdLen) return STATUS_BUFFER_TOO_SMALL;
457
458 /* Copy the application name */
459 RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
460 Message->AppLen = CommandInfo->AppLen;
461 }
462
463 if (CommandInfo->PifLen && Message->PifLen)
464 {
465 if (Message->PifLen < CommandInfo->PifLen) return STATUS_BUFFER_TOO_SMALL;
466
467 /* Copy the PIF file name */
468 RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
469 Message->PifLen = CommandInfo->PifLen;
470 }
471
472 if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen)
473 {
474 if (Message->CurDirectoryLen < CommandInfo->CurDirectoryLen) return STATUS_BUFFER_TOO_SMALL;
475
476 /* Copy the current directory */
477 RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
478 Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
479 }
480
481 if (CommandInfo->EnvLen && Message->EnvLen)
482 {
483 if (Message->EnvLen < CommandInfo->EnvLen) return STATUS_BUFFER_TOO_SMALL;
484
485 /* Copy the environment */
486 RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
487 Message->EnvLen = CommandInfo->EnvLen;
488 }
489
490 /* Copy the startup info */
491 RtlMoveMemory(Message->StartupInfo,
492 &CommandInfo->StartupInfo,
493 sizeof(STARTUPINFOA));
494
495 if (CommandInfo->DesktopLen && Message->DesktopLen)
496 {
497 if (Message->DesktopLen < CommandInfo->DesktopLen) return STATUS_BUFFER_TOO_SMALL;
498
499 /* Copy the desktop name */
500 RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
501 Message->DesktopLen = CommandInfo->DesktopLen;
502 }
503
504 if (CommandInfo->TitleLen && Message->TitleLen)
505 {
506 if (Message->TitleLen < CommandInfo->TitleLen) return STATUS_BUFFER_TOO_SMALL;
507
508 /* Copy the title */
509 RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
510 Message->TitleLen = CommandInfo->TitleLen;
511 }
512
513 if (CommandInfo->ReservedLen && Message->ReservedLen)
514 {
515 if (Message->ReservedLen < CommandInfo->ReservedLen) return STATUS_BUFFER_TOO_SMALL;
516
517 /* Copy the reserved parameter */
518 RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
519 Message->ReservedLen = CommandInfo->ReservedLen;
520 }
521
522 return STATUS_SUCCESS;
523 }
524
525 VOID NTAPI BaseInitializeVDM(VOID)
526 {
527 /* Initialize the list head */
528 InitializeListHead(&VDMConsoleListHead);
529
530 /* Initialize the critical section */
531 RtlInitializeCriticalSection(&DosCriticalSection);
532 RtlInitializeCriticalSection(&WowCriticalSection);
533 }
534
535 /* PUBLIC SERVER APIS *********************************************************/
536
537 CSR_API(BaseSrvCheckVDM)
538 {
539 NTSTATUS Status;
540 PBASE_CHECK_VDM CheckVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CheckVDMRequest;
541 PRTL_CRITICAL_SECTION CriticalSection = NULL;
542 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
543 PVDM_DOS_RECORD DosRecord = NULL;
544 BOOLEAN NewConsoleRecord = FALSE;
545
546 /* Don't do anything if the VDM has been disabled in the registry */
547 if (!BaseSrvIsVdmAllowed()) return STATUS_ACCESS_DENIED;
548
549 /* Validate the message buffers */
550 if (!CsrValidateMessageBuffer(ApiMessage,
551 (PVOID*)&CheckVdmRequest->CmdLine,
552 CheckVdmRequest->CmdLen,
553 sizeof(*CheckVdmRequest->CmdLine))
554 || !CsrValidateMessageBuffer(ApiMessage,
555 (PVOID*)&CheckVdmRequest->AppName,
556 CheckVdmRequest->AppLen,
557 sizeof(*CheckVdmRequest->AppName))
558 || !CsrValidateMessageBuffer(ApiMessage,
559 (PVOID*)&CheckVdmRequest->PifFile,
560 CheckVdmRequest->PifLen,
561 sizeof(*CheckVdmRequest->PifFile))
562 || !CsrValidateMessageBuffer(ApiMessage,
563 (PVOID*)&CheckVdmRequest->CurDirectory,
564 CheckVdmRequest->CurDirectoryLen,
565 sizeof(*CheckVdmRequest->CurDirectory))
566 || !CsrValidateMessageBuffer(ApiMessage,
567 (PVOID*)&CheckVdmRequest->Desktop,
568 CheckVdmRequest->DesktopLen,
569 sizeof(*CheckVdmRequest->Desktop))
570 || !CsrValidateMessageBuffer(ApiMessage,
571 (PVOID*)&CheckVdmRequest->Title,
572 CheckVdmRequest->TitleLen,
573 sizeof(*CheckVdmRequest->Title))
574 || !CsrValidateMessageBuffer(ApiMessage,
575 (PVOID*)&CheckVdmRequest->Reserved,
576 CheckVdmRequest->ReservedLen,
577 sizeof(*CheckVdmRequest->Reserved)))
578 {
579 return STATUS_INVALID_PARAMETER;
580 }
581
582 CriticalSection = (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
583 ? &DosCriticalSection
584 : &WowCriticalSection;
585
586 /* Enter the critical section */
587 RtlEnterCriticalSection(CriticalSection);
588
589 /* Check if this is a DOS or WOW VDM */
590 if (CheckVdmRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
591 {
592 /* Get the console record */
593 Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
594 &ConsoleRecord);
595
596 if (!NT_SUCCESS(Status))
597 {
598 /* Allocate a new console record */
599 ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
600 HEAP_ZERO_MEMORY,
601 sizeof(VDM_CONSOLE_RECORD));
602 if (ConsoleRecord == NULL)
603 {
604 Status = STATUS_NO_MEMORY;
605 goto Cleanup;
606 }
607
608 /* Remember that the console record was allocated here */
609 NewConsoleRecord = TRUE;
610
611 /* Initialize the console record */
612 ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
613 ConsoleRecord->ProcessHandle = CsrGetClientThread()->Process->ProcessHandle;
614 ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
615 ConsoleRecord->ReenterCount = 0;
616 ConsoleRecord->CurrentDirs = NULL;
617 ConsoleRecord->CurDirsLength = 0;
618 ConsoleRecord->SessionId = GetNextDosSesId();
619 InitializeListHead(&ConsoleRecord->DosListHead);
620 }
621
622 /* Allocate a new DOS record */
623 DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
624 HEAP_ZERO_MEMORY,
625 sizeof(VDM_DOS_RECORD));
626 if (DosRecord == NULL)
627 {
628 Status = STATUS_NO_MEMORY;
629 goto Cleanup;
630 }
631
632 /* Initialize the DOS record */
633 DosRecord->State = VDM_NOT_LOADED;
634 DosRecord->ExitCode = 0;
635
636 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
637 if (!NT_SUCCESS(Status)) goto Cleanup;
638
639 /* Return the client event handle */
640 CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
641
642 /* Translate the input structure into a VDM command structure and set it in the DOS record */
643 if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
644 {
645 /* The only possibility is that an allocation failure occurred */
646 Status = STATUS_NO_MEMORY;
647 goto Cleanup;
648 }
649
650 /* Add the DOS record */
651 InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
652
653 if (ConsoleRecord->ServerEvent)
654 {
655 /* Signal the session event */
656 NtSetEvent(ConsoleRecord->ServerEvent, NULL);
657 }
658
659 if (NewConsoleRecord)
660 {
661 /* Add the console record */
662 InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
663 }
664
665 CheckVdmRequest->iTask = ConsoleRecord->SessionId;
666 CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
667 Status = STATUS_SUCCESS;
668 }
669 else
670 {
671 // TODO: NOT IMPLEMENTED
672 UNIMPLEMENTED;
673 Status = STATUS_NOT_IMPLEMENTED;
674 }
675
676 Cleanup:
677 /* Check if it failed */
678 if (!NT_SUCCESS(Status))
679 {
680 /* Free the DOS record */
681 if (DosRecord != NULL)
682 {
683 if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent);
684 if (DosRecord->ClientEvent)
685 {
686 /* Close the remote handle */
687 NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
688 DosRecord->ClientEvent,
689 NULL,
690 NULL,
691 0,
692 0,
693 DUPLICATE_CLOSE_SOURCE);
694 }
695
696 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
697 DosRecord = NULL;
698 }
699
700 /* Free the console record if it was allocated here */
701 if (NewConsoleRecord)
702 {
703 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
704 ConsoleRecord = NULL;
705 }
706 }
707
708 /* Leave the critical section */
709 RtlLeaveCriticalSection(CriticalSection);
710
711 return Status;
712 }
713
714 CSR_API(BaseSrvUpdateVDMEntry)
715 {
716 NTSTATUS Status;
717 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntryRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.UpdateVDMEntryRequest;
718 PRTL_CRITICAL_SECTION CriticalSection = NULL;
719 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
720 PVDM_DOS_RECORD DosRecord = NULL;
721
722 CriticalSection = (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
723 ? &DosCriticalSection
724 : &WowCriticalSection;
725
726 /* Enter the critical section */
727 RtlEnterCriticalSection(CriticalSection);
728
729 /* Check if this is a DOS or WOW VDM */
730 if (UpdateVdmEntryRequest->BinaryType != BINARY_TYPE_SEPARATE_WOW)
731 {
732 if (UpdateVdmEntryRequest->iTask != 0)
733 {
734 /* Get the console record using the task ID */
735 Status = GetConsoleRecordBySessionId(UpdateVdmEntryRequest->iTask,
736 &ConsoleRecord);
737 }
738 else
739 {
740 /* Get the console record using the console handle */
741 Status = BaseSrvGetConsoleRecord(UpdateVdmEntryRequest->ConsoleHandle,
742 &ConsoleRecord);
743 }
744
745 if (!NT_SUCCESS(Status)) goto Cleanup;
746
747 /* Get the primary DOS record */
748 DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
749 VDM_DOS_RECORD,
750 Entry);
751
752 switch (UpdateVdmEntryRequest->EntryIndex)
753 {
754 case VdmEntryUndo:
755 {
756 /* Close the server event handle, the client will close the client handle */
757 NtClose(DosRecord->ServerEvent);
758 DosRecord->ServerEvent = DosRecord->ClientEvent = NULL;
759
760 if (UpdateVdmEntryRequest->VDMCreationState & (VDM_UNDO_PARTIAL | VDM_UNDO_FULL))
761 {
762 /* Remove the DOS record */
763 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
764 RemoveEntryList(&DosRecord->Entry);
765 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
766
767 /*
768 * Since this is an undo, if that was the only DOS record the VDM
769 * won't even start, so the console record should be removed too.
770 */
771 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
772 {
773 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
774 RemoveEntryList(&ConsoleRecord->Entry);
775 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
776 }
777 }
778
779 /* It was successful */
780 Status = STATUS_SUCCESS;
781
782 break;
783 }
784
785 case VdmEntryUpdateProcess:
786 {
787 /* Duplicate the VDM process handle */
788 Status = NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
789 UpdateVdmEntryRequest->VDMProcessHandle,
790 NtCurrentProcess(),
791 &ConsoleRecord->ProcessHandle,
792 0,
793 0,
794 DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
795 if (!NT_SUCCESS(Status)) goto Cleanup;
796
797 /* Create a pair of handles to one event object */
798 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
799 &DosRecord->ClientEvent);
800 if (!NT_SUCCESS(Status)) goto Cleanup;
801
802 /* Return the client event handle */
803 UpdateVdmEntryRequest->WaitObjectForParent = DosRecord->ClientEvent;
804
805 break;
806 }
807
808 case VdmEntryUpdateControlCHandler:
809 {
810 // TODO: NOT IMPLEMENTED
811 DPRINT1("BaseSrvUpdateVDMEntry: VdmEntryUpdateControlCHandler not implemented!");
812 Status = STATUS_NOT_IMPLEMENTED;
813
814 break;
815 }
816
817 default:
818 {
819 /* Invalid */
820 Status = STATUS_INVALID_PARAMETER;
821 }
822 }
823 }
824 else
825 {
826 // TODO: NOT IMPLEMENTED
827 UNIMPLEMENTED;
828 Status = STATUS_NOT_IMPLEMENTED;
829 }
830
831 Cleanup:
832 /* Leave the critical section */
833 RtlLeaveCriticalSection(CriticalSection);
834
835 return Status;
836 }
837
838 CSR_API(BaseSrvGetNextVDMCommand)
839 {
840 NTSTATUS Status;
841 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
842 &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
843 PRTL_CRITICAL_SECTION CriticalSection;
844 PLIST_ENTRY i = NULL;
845 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
846 PVDM_DOS_RECORD DosRecord = NULL;
847
848 /* Validate the message buffers */
849 if (!CsrValidateMessageBuffer(ApiMessage,
850 (PVOID*)&GetNextVdmCommandRequest->CmdLine,
851 GetNextVdmCommandRequest->CmdLen,
852 sizeof(*GetNextVdmCommandRequest->CmdLine))
853 || !CsrValidateMessageBuffer(ApiMessage,
854 (PVOID*)&GetNextVdmCommandRequest->AppName,
855 GetNextVdmCommandRequest->AppLen,
856 sizeof(*GetNextVdmCommandRequest->AppName))
857 || !CsrValidateMessageBuffer(ApiMessage,
858 (PVOID*)&GetNextVdmCommandRequest->PifFile,
859 GetNextVdmCommandRequest->PifLen,
860 sizeof(*GetNextVdmCommandRequest->PifFile))
861 || !CsrValidateMessageBuffer(ApiMessage,
862 (PVOID*)&GetNextVdmCommandRequest->CurDirectory,
863 GetNextVdmCommandRequest->CurDirectoryLen,
864 sizeof(*GetNextVdmCommandRequest->CurDirectory))
865 || !CsrValidateMessageBuffer(ApiMessage,
866 (PVOID*)&GetNextVdmCommandRequest->Env,
867 GetNextVdmCommandRequest->EnvLen,
868 sizeof(*GetNextVdmCommandRequest->Env))
869 || !CsrValidateMessageBuffer(ApiMessage,
870 (PVOID*)&GetNextVdmCommandRequest->Desktop,
871 GetNextVdmCommandRequest->DesktopLen,
872 sizeof(*GetNextVdmCommandRequest->Desktop))
873 || !CsrValidateMessageBuffer(ApiMessage,
874 (PVOID*)&GetNextVdmCommandRequest->Title,
875 GetNextVdmCommandRequest->TitleLen,
876 sizeof(*GetNextVdmCommandRequest->Title))
877 || !CsrValidateMessageBuffer(ApiMessage,
878 (PVOID*)&GetNextVdmCommandRequest->Reserved,
879 GetNextVdmCommandRequest->ReservedLen,
880 sizeof(*GetNextVdmCommandRequest->Reserved))
881 || !CsrValidateMessageBuffer(ApiMessage,
882 (PVOID*)&GetNextVdmCommandRequest->StartupInfo,
883 1,
884 sizeof(STARTUPINFOA)))
885 {
886 return STATUS_INVALID_PARAMETER;
887 }
888
889 CriticalSection = (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
890 ? &WowCriticalSection
891 : &DosCriticalSection;
892
893 /* Enter the critical section */
894 RtlEnterCriticalSection(CriticalSection);
895
896 if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
897 {
898 if (GetNextVdmCommandRequest->iTask != 0)
899 {
900 /* Get the console record using the task ID */
901 Status = GetConsoleRecordBySessionId(GetNextVdmCommandRequest->iTask,
902 &ConsoleRecord);
903 }
904 else
905 {
906 /* Get the console record using the console handle */
907 Status = BaseSrvGetConsoleRecord(GetNextVdmCommandRequest->ConsoleHandle,
908 &ConsoleRecord);
909 }
910
911 /* Make sure we found the console record */
912 if (!NT_SUCCESS(Status)) goto Cleanup;
913
914 /* Return the session ID */
915 GetNextVdmCommandRequest->iTask = ConsoleRecord->SessionId;
916 GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
917
918 if (GetNextVdmCommandRequest->VDMState & VDM_GET_FIRST_COMMAND)
919 {
920 /* Check if the DOS record list is empty */
921 if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
922 {
923 Status = STATUS_INVALID_PARAMETER;
924 goto Cleanup;
925 }
926
927 /* Get the first DOS record */
928 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, VDM_DOS_RECORD, Entry);
929
930 /* Make sure its command information is still there */
931 if (DosRecord->CommandInfo == NULL)
932 {
933 Status = STATUS_INVALID_PARAMETER;
934 goto Cleanup;
935 }
936
937 /* Fill the command information */
938 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
939 goto Cleanup;
940 }
941
942 /* Check if we should set the state of a running DOS record to ready */
943 if (!(GetNextVdmCommandRequest->VDMState
944 & (VDM_FLAG_FIRST_TASK | VDM_FLAG_RETRY | VDM_FLAG_NESTED_TASK)))
945 {
946 /* Search for a DOS record that is currently running */
947 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
948 {
949 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
950 if (DosRecord->State == VDM_NOT_READY) break;
951 }
952
953 /* Check if we found any */
954 if (i == &ConsoleRecord->DosListHead)
955 {
956 Status = STATUS_INVALID_PARAMETER;
957 goto Cleanup;
958 }
959
960 /* Set the exit code */
961 DosRecord->ExitCode = GetNextVdmCommandRequest->ExitCode;
962
963 /* Update the VDM state */
964 DosRecord->State = VDM_READY;
965
966 /* Notify all waiting threads that the task is finished */
967 NtSetEvent(DosRecord->ServerEvent, NULL);
968 NtClose(DosRecord->ServerEvent);
969 DosRecord->ServerEvent = NULL;
970 }
971
972 /* Search for a DOS record that isn't loaded yet */
973 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
974 {
975 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
976 if (DosRecord->State == VDM_NOT_LOADED) break;
977 }
978
979 if (i != &ConsoleRecord->DosListHead)
980 {
981 /* DOS tasks which haven't been loaded yet should have a command info structure */
982 ASSERT(DosRecord->CommandInfo != NULL);
983
984 /* Check if the caller only wants environment data */
985 if (GetNextVdmCommandRequest->VDMState & VDM_GET_ENVIRONMENT)
986 {
987 if (GetNextVdmCommandRequest->EnvLen < DosRecord->CommandInfo->EnvLen)
988 {
989 /* Not enough space was reserved */
990 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
991 Status = STATUS_BUFFER_OVERFLOW;
992 goto Cleanup;
993 }
994
995 /* Copy the environment data */
996 RtlMoveMemory(GetNextVdmCommandRequest->Env,
997 DosRecord->CommandInfo->Env,
998 DosRecord->CommandInfo->EnvLen);
999
1000 /* Return the actual size to the caller */
1001 GetNextVdmCommandRequest->EnvLen = DosRecord->CommandInfo->EnvLen;
1002 }
1003 else
1004 {
1005 /* Fill the command information */
1006 Status = BaseSrvFillCommandInfo(DosRecord->CommandInfo, GetNextVdmCommandRequest);
1007
1008 /* Free the command information, it's no longer needed */
1009 BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1010 DosRecord->CommandInfo = NULL;
1011
1012 /* Update the VDM state */
1013 GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY;
1014 }
1015
1016 Status = STATUS_SUCCESS;
1017 goto Cleanup;
1018 }
1019 }
1020 else
1021 {
1022 // TODO: WOW SUPPORT NOT IMPLEMENTED
1023 Status = STATUS_NOT_IMPLEMENTED;
1024 goto Cleanup;
1025 }
1026
1027 /* There is no command yet */
1028 if ((GetNextVdmCommandRequest->VDMState & (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
1029 != (VDM_FLAG_DONT_WAIT | VDM_FLAG_RETRY))
1030 {
1031 if (ConsoleRecord->ServerEvent)
1032 {
1033 /* Reset the event */
1034 NtResetEvent(ConsoleRecord->ServerEvent, NULL);
1035 }
1036 else
1037 {
1038 /* Create a pair of wait handles */
1039 Status = BaseSrvCreatePairWaitHandles(&ConsoleRecord->ServerEvent,
1040 &ConsoleRecord->ClientEvent);
1041 if (!NT_SUCCESS(Status)) goto Cleanup;
1042 }
1043
1044 /* Return the client event handle */
1045 GetNextVdmCommandRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
1046 }
1047
1048 Cleanup:
1049 /* Leave the critical section */
1050 RtlLeaveCriticalSection(CriticalSection);
1051
1052 return Status;
1053 }
1054
1055 CSR_API(BaseSrvExitVDM)
1056 {
1057 NTSTATUS Status;
1058 PBASE_EXIT_VDM ExitVdmRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.ExitVDMRequest;
1059 PRTL_CRITICAL_SECTION CriticalSection = NULL;
1060 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1061 PVDM_DOS_RECORD DosRecord;
1062
1063 CriticalSection = (ExitVdmRequest->iWowTask == 0)
1064 ? &DosCriticalSection
1065 : &WowCriticalSection;
1066
1067 /* Enter the critical section */
1068 RtlEnterCriticalSection(CriticalSection);
1069
1070 if (ExitVdmRequest->iWowTask == 0)
1071 {
1072 /* Get the console record */
1073 Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
1074 if (!NT_SUCCESS(Status)) goto Cleanup;
1075
1076 /* Cleanup the DOS records */
1077 while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
1078 {
1079 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
1080 VDM_DOS_RECORD,
1081 Entry);
1082
1083 /* Set the event and close it */
1084 NtSetEvent(DosRecord->ServerEvent, NULL);
1085 NtClose(DosRecord->ServerEvent);
1086
1087 /* Remove the DOS entry */
1088 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1089 RemoveEntryList(&DosRecord->Entry);
1090 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1091 }
1092
1093 if (ConsoleRecord->CurrentDirs != NULL)
1094 {
1095 /* Free the current directories */
1096 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
1097 ConsoleRecord->CurrentDirs = NULL;
1098 ConsoleRecord->CurDirsLength = 0;
1099 }
1100
1101 /* Close the event handle */
1102 if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
1103
1104 /* Remove the console record */
1105 RemoveEntryList(&ConsoleRecord->Entry);
1106 RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
1107 }
1108 else
1109 {
1110 // TODO: NOT IMPLEMENTED
1111 UNIMPLEMENTED;
1112 Status = STATUS_NOT_IMPLEMENTED;
1113 }
1114
1115 Cleanup:
1116 /* Leave the critical section */
1117 RtlLeaveCriticalSection(CriticalSection);
1118
1119 return Status;
1120 }
1121
1122 CSR_API(BaseSrvIsFirstVDM)
1123 {
1124 PBASE_IS_FIRST_VDM IsFirstVDMRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.IsFirstVDMRequest;
1125
1126 /* Return the result */
1127 IsFirstVDMRequest->FirstVDM = FirstVDM;
1128
1129 /* Clear the first VDM flag */
1130 FirstVDM = FALSE;
1131
1132 return STATUS_SUCCESS;
1133 }
1134
1135 CSR_API(BaseSrvGetVDMExitCode)
1136 {
1137 NTSTATUS Status;
1138 PBASE_GET_VDM_EXIT_CODE GetVDMExitCodeRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetVDMExitCodeRequest;
1139 PLIST_ENTRY i = NULL;
1140 PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
1141 PVDM_DOS_RECORD DosRecord = NULL;
1142
1143 /* Enter the critical section */
1144 RtlEnterCriticalSection(&DosCriticalSection);
1145
1146 /* Get the console record */
1147 Status = BaseSrvGetConsoleRecord(GetVDMExitCodeRequest->ConsoleHandle, &ConsoleRecord);
1148 if (!NT_SUCCESS(Status)) goto Cleanup;
1149
1150 /* Search for a DOS record that has the same parent process handle */
1151 for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
1152 {
1153 DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
1154 if (DosRecord->ClientEvent == GetVDMExitCodeRequest->hParent) break;
1155 }
1156
1157 /* Check if no DOS record was found */
1158 if (i == &ConsoleRecord->DosListHead)
1159 {
1160 Status = STATUS_NOT_FOUND;
1161 goto Cleanup;
1162 }
1163
1164 /* Check if this task is still running */
1165 if (DosRecord->State == VDM_READY)
1166 {
1167 GetVDMExitCodeRequest->ExitCode = STATUS_PENDING;
1168 goto Cleanup;
1169 }
1170
1171 /* Return the exit code */
1172 GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
1173
1174 /* Since this is a zombie task record, remove it */
1175 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
1176 RemoveEntryList(&DosRecord->Entry);
1177 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
1178
1179 Cleanup:
1180 /* Leave the critical section */
1181 RtlLeaveCriticalSection(&DosCriticalSection);
1182
1183 return Status;
1184 }
1185
1186 CSR_API(BaseSrvSetReenterCount)
1187 {
1188 NTSTATUS Status = STATUS_SUCCESS;
1189 PBASE_SET_REENTER_COUNT SetReenterCountRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetReenterCountRequest;
1190 PVDM_CONSOLE_RECORD ConsoleRecord;
1191
1192 /* Enter the critical section */
1193 RtlEnterCriticalSection(&DosCriticalSection);
1194
1195 /* Get the console record */
1196 Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
1197 if (!NT_SUCCESS(Status)) goto Cleanup;
1198
1199 if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
1200 else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
1201 {
1202 ConsoleRecord->ReenterCount--;
1203 if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
1204 }
1205 else Status = STATUS_INVALID_PARAMETER;
1206
1207 Cleanup:
1208 /* Leave the critical section */
1209 RtlLeaveCriticalSection(&DosCriticalSection);
1210
1211 return Status;
1212 }
1213
1214 CSR_API(BaseSrvSetVDMCurDirs)
1215 {
1216 NTSTATUS Status;
1217 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1218 PVDM_CONSOLE_RECORD ConsoleRecord;
1219 PCHAR Buffer = NULL;
1220
1221 /* Validate the input buffer */
1222 if (!CsrValidateMessageBuffer(ApiMessage,
1223 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1224 VDMCurrentDirsRequest->cchCurDirs,
1225 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1226 {
1227 return STATUS_INVALID_PARAMETER;
1228 }
1229
1230 /* Enter the critical section */
1231 RtlEnterCriticalSection(&DosCriticalSection);
1232
1233 /* Find the console record */
1234 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1235 if (!NT_SUCCESS(Status)) goto Cleanup;
1236
1237 if (ConsoleRecord->CurrentDirs == NULL)
1238 {
1239 /* Allocate memory for the current directory information */
1240 Buffer = RtlAllocateHeap(BaseSrvHeap,
1241 HEAP_ZERO_MEMORY,
1242 VDMCurrentDirsRequest->cchCurDirs);
1243 }
1244 else
1245 {
1246 /* Resize the amount of allocated memory */
1247 Buffer = RtlReAllocateHeap(BaseSrvHeap,
1248 HEAP_ZERO_MEMORY,
1249 ConsoleRecord->CurrentDirs,
1250 VDMCurrentDirsRequest->cchCurDirs);
1251 }
1252
1253 if (Buffer == NULL)
1254 {
1255 /* Allocation failed */
1256 Status = STATUS_NO_MEMORY;
1257 goto Cleanup;
1258 }
1259
1260 /* Update the console record */
1261 ConsoleRecord->CurrentDirs = Buffer;
1262 ConsoleRecord->CurDirsLength = VDMCurrentDirsRequest->cchCurDirs;
1263
1264 /* Copy the data */
1265 RtlMoveMemory(ConsoleRecord->CurrentDirs,
1266 VDMCurrentDirsRequest->lpszzCurDirs,
1267 VDMCurrentDirsRequest->cchCurDirs);
1268
1269 Cleanup:
1270 /* Leave the critical section */
1271 RtlLeaveCriticalSection(&DosCriticalSection);
1272
1273 return Status;
1274 }
1275
1276 CSR_API(BaseSrvGetVDMCurDirs)
1277 {
1278 NTSTATUS Status;
1279 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.VDMCurrentDirsRequest;
1280 PVDM_CONSOLE_RECORD ConsoleRecord;
1281
1282 /* Validate the output buffer */
1283 if (!CsrValidateMessageBuffer(ApiMessage,
1284 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs,
1285 VDMCurrentDirsRequest->cchCurDirs,
1286 sizeof(*VDMCurrentDirsRequest->lpszzCurDirs)))
1287 {
1288 return STATUS_INVALID_PARAMETER;
1289 }
1290
1291 /* Enter the critical section */
1292 RtlEnterCriticalSection(&DosCriticalSection);
1293
1294 /* Find the console record */
1295 Status = BaseSrvGetConsoleRecord(VDMCurrentDirsRequest->ConsoleHandle, &ConsoleRecord);
1296 if (!NT_SUCCESS(Status)) goto Cleanup;
1297
1298 /* Return the actual size of the current directory information */
1299 VDMCurrentDirsRequest->cchCurDirs = ConsoleRecord->CurDirsLength;
1300
1301 /* Check if the buffer is large enough */
1302 if (VDMCurrentDirsRequest->cchCurDirs < ConsoleRecord->CurDirsLength)
1303 {
1304 Status = STATUS_BUFFER_TOO_SMALL;
1305 goto Cleanup;
1306 }
1307
1308 /* Copy the data */
1309 RtlMoveMemory(VDMCurrentDirsRequest->lpszzCurDirs,
1310 ConsoleRecord->CurrentDirs,
1311 ConsoleRecord->CurDirsLength);
1312
1313 Cleanup:
1314 /* Leave the critical section */
1315 RtlLeaveCriticalSection(&DosCriticalSection);
1316
1317 return Status;
1318 }
1319
1320 CSR_API(BaseSrvBatNotification)
1321 {
1322 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1323 return STATUS_NOT_IMPLEMENTED;
1324 }
1325
1326 CSR_API(BaseSrvRegisterWowExec)
1327 {
1328 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1329 return STATUS_NOT_IMPLEMENTED;
1330 }
1331
1332 CSR_API(BaseSrvRefreshIniFileMapping)
1333 {
1334 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1335 return STATUS_NOT_IMPLEMENTED;
1336 }
1337
1338 /* EOF */