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