[CONSRV]
[reactos.git] / win32ss / user / consrv / handle.c
1 /*
2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/handle.c
5 * PURPOSE: Console IO Handle functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "consrv.h"
12 #include "conio.h"
13
14 //#define NDEBUG
15 #include <debug.h>
16
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 static INT
21 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
22 {
23 Object_t *Object = Entry->Object;
24
25 DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
26
27 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
28 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
29 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
30 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
31
32 Object->HandleCount += Change;
33
34 return Object->HandleCount;
35 }
36
37 static VOID
38 Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry)
39 {
40 Object_t *Object = Entry->Object;
41 EnterCriticalSection(&Object->Console->Lock);
42 AdjustHandleCounts(Entry, +1);
43 LeaveCriticalSection(&Object->Console->Lock);
44 }
45
46 static VOID
47 Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
48 {
49 Object_t *Object = Entry->Object;
50 if (Object != NULL)
51 {
52 PCSRSS_CONSOLE Console = Object->Console;
53 EnterCriticalSection(&Console->Lock);
54
55 /* If the last handle to a screen buffer is closed, delete it... */
56 if (AdjustHandleCounts(Entry, -1) == 0)
57 {
58 if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
59 {
60 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
61 /* ...unless it's the only buffer left. Windows allows deletion
62 * even of the last buffer, but having to deal with a lack of
63 * any active buffer might be error-prone. */
64 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
65 ConioDeleteScreenBuffer(Buffer);
66 }
67 else if (Object->Type == CONIO_CONSOLE_MAGIC)
68 {
69 /* TODO: FIXME: Destroy here the console ?? */
70 // ConioDeleteConsole(Console);
71 }
72 }
73
74 LeaveCriticalSection(&Console->Lock);
75 Entry->Object = NULL;
76 }
77 }
78
79
80 /* FUNCTIONS *****************************************************************/
81
82 NTSTATUS
83 FASTCALL
84 Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
85 PHANDLE Handle,
86 Object_t *Object,
87 DWORD Access,
88 BOOL Inheritable,
89 DWORD ShareMode)
90 {
91 ULONG i;
92 PCSRSS_HANDLE Block;
93
94 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
95
96 for (i = 0; i < ProcessData->HandleTableSize; i++)
97 {
98 if (ProcessData->HandleTable[i].Object == NULL)
99 {
100 break;
101 }
102 }
103 if (i >= ProcessData->HandleTableSize)
104 {
105 Block = RtlAllocateHeap(ConSrvHeap,
106 HEAP_ZERO_MEMORY,
107 (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
108 if (Block == NULL)
109 {
110 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
111 return STATUS_UNSUCCESSFUL;
112 }
113 RtlCopyMemory(Block,
114 ProcessData->HandleTable,
115 ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
116 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
117 ProcessData->HandleTable = Block;
118 ProcessData->HandleTableSize += 64;
119 }
120 ProcessData->HandleTable[i].Object = Object;
121 ProcessData->HandleTable[i].Access = Access;
122 ProcessData->HandleTable[i].Inheritable = Inheritable;
123 ProcessData->HandleTable[i].ShareMode = ShareMode;
124 Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
125 *Handle = UlongToHandle((i << 2) | 0x3);
126 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
127 return STATUS_SUCCESS;
128 }
129
130 NTSTATUS
131 FASTCALL
132 Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
133 HANDLE Handle)
134 {
135 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
136 Object_t *Object;
137
138 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
139
140 if (h >= ProcessData->HandleTableSize ||
141 (Object = ProcessData->HandleTable[h].Object) == NULL)
142 {
143 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
144 return STATUS_INVALID_HANDLE;
145 }
146
147 DPRINT1("Win32CsrReleaseObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
148 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
149
150 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
151
152 return STATUS_SUCCESS;
153 }
154
155 NTSTATUS
156 FASTCALL
157 Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
158 HANDLE Handle,
159 Object_t **Object,
160 DWORD Access,
161 LONG Type)
162 {
163 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
164
165 DPRINT("Win32CsrLockObject, Object: %x, %x, %x\n",
166 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
167
168 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
169
170 if ( !IsConsoleHandle(Handle) ||
171 h >= ProcessData->HandleTableSize ||
172 (*Object = ProcessData->HandleTable[h].Object) == NULL ||
173 ~ProcessData->HandleTable[h].Access & Access ||
174 (Type != 0 && (*Object)->Type != Type) )
175 {
176 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
177 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
178 return STATUS_INVALID_HANDLE;
179 }
180
181 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
182 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
183
184 EnterCriticalSection(&((*Object)->Console->Lock));
185 return STATUS_SUCCESS;
186 }
187
188 VOID FASTCALL
189 Win32CsrUnlockConsole(PCSRSS_CONSOLE Console)
190 {
191 LeaveCriticalSection(&Console->Lock);
192
193 /* Decrement reference count */
194 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
195 ConioDeleteConsole(Console);
196 }
197
198 VOID
199 FASTCALL
200 Win32CsrUnlockObject(Object_t *Object)
201 {
202 Win32CsrUnlockConsole(Object->Console);
203 }
204
205
206
207 /** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/
208 NTSTATUS
209 NTAPI
210 ConsoleNewProcess(PCSR_PROCESS SourceProcess,
211 PCSR_PROCESS TargetProcess)
212 {
213 /**************************************************************************
214 * This function is called whenever a new process (GUI or CUI) is created.
215 *
216 * Copy the parent's handles table here if both the parent and the child
217 * processes are CUI. If we must actually create our proper console (and
218 * thus do not inherit from the console handles of the parent's), then we
219 * will clean this table in the next ConsoleConnect call. Why we are doing
220 * this? It's because here, we still don't know whether or not we must create
221 * a new console instead of inherit it from the parent, and, because in
222 * ConsoleConnect we don't have any reference to the parent process anymore.
223 **************************************************************************/
224
225 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
226 ULONG i;
227
228 DPRINT1("ConsoleNewProcess inside\n");
229 DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
230
231 /* An empty target process is invalid */
232 if (!TargetProcess)
233 return STATUS_INVALID_PARAMETER;
234
235 DPRINT1("ConsoleNewProcess - OK\n");
236
237 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
238 DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData);
239
240 /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
241
242 /* Initialize the new (target) process */
243 TargetProcessData->Process = TargetProcess;
244 TargetProcessData->ConsoleEvent = NULL;
245 TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
246 // TargetProcessData->bInheritHandles = FALSE;
247 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
248
249 // Testing
250 TargetProcessData->HandleTableSize = 0;
251 TargetProcessData->HandleTable = NULL;
252
253 /* HACK */ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION));
254 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
255
256 /* Do nothing if the source process is NULL */
257 if (!SourceProcess)
258 return STATUS_SUCCESS;
259
260 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
261 DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData);
262
263 /*
264 * If both of the processes (parent and new child) are console applications,
265 * then try to inherit handles from the parent process.
266 */
267 if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
268 TargetProcessData->ConsoleApp )
269 {
270 /*
271 if (TargetProcessData->HandleTableSize)
272 {
273 return STATUS_INVALID_PARAMETER;
274 }
275 */
276
277 DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n");
278 /* Temporary "inherit" the console from the parent */
279 TargetProcessData->ParentConsole = SourceProcessData->Console;
280 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
281 DPRINT1("ConsoleNewProcess - Copy the handle table (2)\n");
282
283 /* Allocate a new handle table for the child process */
284 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
285 HEAP_ZERO_MEMORY,
286 SourceProcessData->HandleTableSize
287 * sizeof(CSRSS_HANDLE));
288 if (TargetProcessData->HandleTable == NULL)
289 {
290 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
291 return STATUS_UNSUCCESSFUL;
292 }
293
294 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
295
296 /*
297 * Parse the parent process' handles table and, for each handle,
298 * do a copy of it and reference it, if the handle is inheritable.
299 */
300 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
301 {
302 if (SourceProcessData->HandleTable[i].Object != NULL &&
303 SourceProcessData->HandleTable[i].Inheritable)
304 {
305 /*
306 * Copy the handle data and increment the reference count of the
307 * pointed object (via the call to Win32CsrCreateHandleEntry).
308 */
309 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
310 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
311 }
312 }
313
314 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
315 }
316 else
317 {
318 DPRINT1("ConsoleNewProcess - We don't launch a Console process : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
319 }
320
321 return STATUS_SUCCESS;
322 }
323
324 // Temporary ; move it to a header.
325 NTSTATUS WINAPI CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd);
326
327 NTSTATUS
328 NTAPI
329 ConsoleConnect(IN PCSR_PROCESS CsrProcess,
330 IN OUT PVOID ConnectionInfo,
331 IN OUT PULONG ConnectionInfoLength)
332 {
333 /**************************************************************************
334 * This function is called whenever a CUI new process is created.
335 **************************************************************************/
336
337 NTSTATUS Status = STATUS_SUCCESS;
338 PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
339 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
340 BOOLEAN NewConsole = FALSE;
341 // PCSRSS_CONSOLE Console = NULL;
342
343 DPRINT1("ConsoleConnect\n");
344
345 if ( ConnectionInfo == NULL ||
346 ConnectionInfoLength == NULL ||
347 *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
348 {
349 DPRINT1("CONSRV: Connection failed\n");
350 return STATUS_UNSUCCESSFUL;
351 }
352
353 /* If we don't need a console, then get out of here */
354 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
355 {
356 DPRINT("ConsoleConnect - No console needed\n");
357 return STATUS_SUCCESS;
358 }
359
360 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
361
362 /* If we don't have a console, then create a new one... */
363 if (!ConnectInfo->Console ||
364 ConnectInfo->Console != ProcessData->ParentConsole)
365 {
366 // PCSRSS_CONSOLE Console;
367
368 DPRINT1("ConsoleConnect - Allocate a new console\n");
369
370 /* Initialize a new Console */
371 NewConsole = TRUE;
372 Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd);
373 if (!NT_SUCCESS(Status))
374 {
375 DPRINT1("Console initialization failed\n");
376 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
377 return Status;
378 }
379 }
380 else /* We inherit it from the parent */
381 {
382 DPRINT1("ConsoleConnect - Reuse current (parent's) console\n");
383
384 /* Reuse our current console */
385 NewConsole = FALSE;
386 ProcessData->Console = ConnectInfo->Console;
387 }
388
389 /* Insert the process into the processes list of the console */
390 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
391
392 /* Return it to the caller */
393 ConnectInfo->Console = ProcessData->Console;
394
395 /* Add a reference count because the process is tied to the console */
396 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
397
398 if (NewConsole /* || !ProcessData->bInheritHandles */)
399 {
400 /*
401 * We've just created a new console. However when ConsoleNewProcess was
402 * called, we didn't know that we wanted to create a new console and
403 * therefore, we by default inherited the handles table from our parent
404 * process. It's only now that we notice that in fact we do not need
405 * them, because we've created a new console and thus we must use it.
406 *
407 * Therefore, free our handles table and recreate a new one.
408 */
409
410 ULONG i;
411
412 /* Close all console handles and free the handle table memory */
413 for (i = 0; i < ProcessData->HandleTableSize; i++)
414 {
415 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
416 }
417 ProcessData->HandleTableSize = 0;
418 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
419 ProcessData->HandleTable = NULL;
420
421 /*
422 * Create a new handle table - Insert the IO handles
423 */
424
425 /* Insert the Input handle */
426 Status = Win32CsrInsertObject(ProcessData,
427 &ConnectInfo->InputHandle,
428 &ProcessData->Console->Header,
429 GENERIC_READ | GENERIC_WRITE,
430 TRUE,
431 FILE_SHARE_READ | FILE_SHARE_WRITE);
432 if (!NT_SUCCESS(Status))
433 {
434 DPRINT1("Failed to insert the input handle\n");
435 ConioDeleteConsole(ProcessData->Console);
436 ProcessData->Console = NULL;
437 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
438 return Status;
439 }
440
441 /* Insert the Output handle */
442 Status = Win32CsrInsertObject(ProcessData,
443 &ConnectInfo->OutputHandle,
444 &ProcessData->Console->ActiveBuffer->Header,
445 GENERIC_READ | GENERIC_WRITE,
446 TRUE,
447 FILE_SHARE_READ | FILE_SHARE_WRITE);
448 if (!NT_SUCCESS(Status))
449 {
450 DPRINT1("Failed to insert the output handle\n");
451 ConioDeleteConsole(ProcessData->Console);
452 Win32CsrReleaseObject(ProcessData,
453 ConnectInfo->InputHandle);
454 ProcessData->Console = NULL;
455 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
456 return Status;
457 }
458
459 /* Insert the Error handle */
460 Status = Win32CsrInsertObject(ProcessData,
461 &ConnectInfo->ErrorHandle,
462 &ProcessData->Console->ActiveBuffer->Header,
463 GENERIC_READ | GENERIC_WRITE,
464 TRUE,
465 FILE_SHARE_READ | FILE_SHARE_WRITE);
466 if (!NT_SUCCESS(Status))
467 {
468 DPRINT1("Failed to insert the error handle\n");
469 ConioDeleteConsole(ProcessData->Console);
470 Win32CsrReleaseObject(ProcessData,
471 ConnectInfo->OutputHandle);
472 Win32CsrReleaseObject(ProcessData,
473 ConnectInfo->InputHandle);
474 ProcessData->Console = NULL;
475 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
476 return Status;
477 }
478 }
479
480 /* Duplicate the Event */
481 Status = NtDuplicateObject(NtCurrentProcess(),
482 ProcessData->Console->ActiveEvent,
483 ProcessData->Process->ProcessHandle,
484 &ProcessData->ConsoleEvent,
485 EVENT_ALL_ACCESS, 0, 0);
486 if (!NT_SUCCESS(Status))
487 {
488 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
489 ConioDeleteConsole(ProcessData->Console);
490 if (NewConsole /* || !ProcessData->bInheritHandles */)
491 {
492 Win32CsrReleaseObject(ProcessData,
493 ConnectInfo->ErrorHandle);
494 Win32CsrReleaseObject(ProcessData,
495 ConnectInfo->OutputHandle);
496 Win32CsrReleaseObject(ProcessData,
497 ConnectInfo->InputHandle);
498 }
499 ProcessData->Console = NULL;
500 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
501 return Status;
502 }
503 /* Input Wait Handle */
504 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
505
506 /* Set the Ctrl Dispatcher */
507 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
508 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
509
510 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
511 return STATUS_SUCCESS;
512 }
513
514 VOID
515 WINAPI
516 Win32CsrReleaseConsole(PCSR_PROCESS Process)
517 {
518 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
519 PCSRSS_CONSOLE Console;
520 ULONG i;
521
522 DPRINT1("Win32CsrReleaseConsole\n");
523
524 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
525
526 /* Close all console handles and free the handle table memory */
527 for (i = 0; i < ProcessData->HandleTableSize; i++)
528 {
529 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
530 }
531 ProcessData->HandleTableSize = 0;
532 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
533 ProcessData->HandleTable = NULL;
534
535 /* Detach process from console */
536 Console = ProcessData->Console;
537 if (Console != NULL)
538 {
539 DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
540 ProcessData->Console = NULL;
541 EnterCriticalSection(&Console->Lock);
542 RemoveEntryList(&ProcessData->ConsoleLink);
543 Win32CsrUnlockConsole(Console);
544 //CloseHandle(ProcessData->ConsoleEvent);
545 //ProcessData->ConsoleEvent = NULL;
546 }
547
548 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
549 }
550
551 VOID
552 WINAPI
553 ConsoleDisconnect(PCSR_PROCESS Process)
554 {
555 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
556
557 /**************************************************************************
558 * This function is called whenever a new process (GUI or CUI) is destroyed.
559 *
560 * Only do something if the process is a CUI. <-- modify this behaviour if
561 * we deal with a GUI which
562 * quits and acquired a
563 * console...
564 **************************************************************************/
565
566 DPRINT1("ConsoleDisconnect called\n");
567 // if (ProcessData->Console != NULL)
568 if (ProcessData->ConsoleApp)
569 {
570 DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n");
571 Win32CsrReleaseConsole(Process);
572 }
573
574 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
575 }
576
577
578
579 CSR_API(SrvCloseHandle)
580 {
581 PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
582
583 return Win32CsrReleaseObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
584 CloseHandleRequest->Handle);
585 }
586
587 CSR_API(SrvVerifyConsoleIoHandle)
588 {
589 NTSTATUS Status = STATUS_SUCCESS;
590 PCSRSS_VERIFY_HANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
591 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
592 HANDLE Handle = VerifyHandleRequest->Handle;
593 ULONG_PTR Index = (ULONG_PTR)Handle >> 2;
594
595 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
596
597 if (!IsConsoleHandle(Handle) ||
598 Index >= ProcessData->HandleTableSize ||
599 ProcessData->HandleTable[Index].Object == NULL)
600 {
601 DPRINT("CsrVerifyObject failed\n");
602 Status = STATUS_INVALID_HANDLE;
603 }
604
605 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
606
607 return Status;
608 }
609
610 CSR_API(SrvDuplicateHandle)
611 {
612 PCSRSS_HANDLE Entry;
613 DWORD DesiredAccess;
614 PCSRSS_DUPLICATE_HANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
615 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
616 HANDLE Handle = DuplicateHandleRequest->Handle;
617 ULONG_PTR Index = (ULONG_PTR)Handle >> 2;
618
619 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
620
621 if ( /** !IsConsoleHandle(Handle) || **/
622 Index >= ProcessData->HandleTableSize ||
623 (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
624 {
625 DPRINT1("Couldn't duplicate invalid handle %p\n", Handle);
626 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
627 return STATUS_INVALID_HANDLE;
628 }
629
630 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
631 {
632 DesiredAccess = Entry->Access;
633 }
634 else
635 {
636 DesiredAccess = DuplicateHandleRequest->Access;
637 /* Make sure the source handle has all the desired flags */
638 if (~Entry->Access & DesiredAccess)
639 {
640 DPRINT1("Handle %p only has access %X; requested %X\n",
641 Handle, Entry->Access, DesiredAccess);
642 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
643 return STATUS_INVALID_PARAMETER;
644 }
645 }
646
647 ApiMessage->Status = Win32CsrInsertObject(ProcessData,
648 &DuplicateHandleRequest->Handle, // Use the new handle value!
649 Entry->Object,
650 DesiredAccess,
651 DuplicateHandleRequest->Inheritable,
652 Entry->ShareMode);
653 if (NT_SUCCESS(ApiMessage->Status) &&
654 DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
655 {
656 Win32CsrCloseHandleEntry(Entry);
657 }
658
659 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
660 return ApiMessage->Status;
661 }
662
663 /**
664 CSR_API(CsrGetInputWaitHandle)
665 {
666 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
667
668 GetConsoleInputWaitHandle->InputWaitHandle =
669 ConsoleGetPerProcessData(CsrGetClientThread()->Process)->ConsoleEvent;
670
671 return STATUS_SUCCESS;
672 }
673 **/
674
675 /* EOF */