[CSR/BASESRV/CONSRV/WINSRV]
[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: 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 typedef struct _CSRSS_HANDLE
19 {
20 Object_t *Object;
21 DWORD Access;
22 BOOL Inheritable;
23 DWORD ShareMode;
24 } CSRSS_HANDLE, *PCSRSS_HANDLE;
25
26
27 /* FUNCTIONS *****************************************************************/
28
29 static
30 BOOL
31 CsrIsConsoleHandle(HANDLE Handle)
32 {
33 return ((ULONG_PTR)Handle & 0x10000003) == 0x3;
34 }
35
36 static INT
37 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
38 {
39 Object_t *Object = Entry->Object;
40 if (Entry->Access & GENERIC_READ) Object->AccessRead += Change;
41 if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change;
42 if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change;
43 if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
44 Object->HandleCount += Change;
45 return Object->HandleCount;
46 }
47
48 static VOID
49 Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry)
50 {
51 Object_t *Object = Entry->Object;
52 EnterCriticalSection(&Object->Console->Lock);
53 AdjustHandleCounts(Entry, +1);
54 LeaveCriticalSection(&Object->Console->Lock);
55 }
56
57 static VOID
58 Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
59 {
60 Object_t *Object = Entry->Object;
61 if (Object != NULL)
62 {
63 PCSRSS_CONSOLE Console = Object->Console;
64 EnterCriticalSection(&Console->Lock);
65 /* If the last handle to a screen buffer is closed, delete it */
66 if (AdjustHandleCounts(Entry, -1) == 0
67 && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
68 {
69 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
70 /* ...unless it's the only buffer left. Windows allows deletion
71 * even of the last buffer, but having to deal with a lack of
72 * any active buffer might be error-prone. */
73 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
74 ConioDeleteScreenBuffer(Buffer);
75 }
76 LeaveCriticalSection(&Console->Lock);
77 Entry->Object = NULL;
78 }
79 }
80
81 NTSTATUS
82 FASTCALL
83 Win32CsrReleaseObject(PCSR_PROCESS ProcessData,
84 HANDLE Handle)
85 {
86 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
87 Object_t *Object;
88
89 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
90 if (h >= ProcessData->HandleTableSize
91 || (Object = ProcessData->HandleTable[h].Object) == NULL)
92 {
93 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
94 return STATUS_INVALID_HANDLE;
95 }
96 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
97 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
98 return STATUS_SUCCESS;
99 }
100
101 NTSTATUS
102 FASTCALL
103 Win32CsrLockObject(PCSR_PROCESS ProcessData,
104 HANDLE Handle,
105 Object_t **Object,
106 DWORD Access,
107 LONG Type)
108 {
109 ULONG_PTR h = (ULONG_PTR)Handle >> 2;
110
111 DPRINT("CsrGetObject, Object: %x, %x, %x\n",
112 Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
113
114 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
115 if (!CsrIsConsoleHandle(Handle) || h >= ProcessData->HandleTableSize
116 || (*Object = ProcessData->HandleTable[h].Object) == NULL
117 || ~ProcessData->HandleTable[h].Access & Access
118 || (Type != 0 && (*Object)->Type != Type))
119 {
120 DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
121 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
122 return STATUS_INVALID_HANDLE;
123 }
124 _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
125 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
126
127 EnterCriticalSection(&((*Object)->Console->Lock));
128 return STATUS_SUCCESS;
129 }
130
131 VOID
132 FASTCALL
133 Win32CsrUnlockObject(Object_t *Object)
134 {
135 PCSRSS_CONSOLE Console = Object->Console;
136 LeaveCriticalSection(&Console->Lock);
137 /* dec ref count */
138 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
139 ConioDeleteConsole(&Console->Header);
140 }
141
142 VOID
143 WINAPI
144 Win32CsrReleaseConsole(PCSR_PROCESS ProcessData)
145 {
146 PCSRSS_CONSOLE Console;
147 ULONG i;
148
149 /* Close all console handles and detach process from console */
150 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
151
152 for (i = 0; i < ProcessData->HandleTableSize; i++)
153 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
154 ProcessData->HandleTableSize = 0;
155 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
156 ProcessData->HandleTable = NULL;
157
158 Console = ProcessData->Console;
159 if (Console != NULL)
160 {
161 ProcessData->Console = NULL;
162 EnterCriticalSection(&Console->Lock);
163 RemoveEntryList(&ProcessData->ConsoleLink);
164 LeaveCriticalSection(&Console->Lock);
165 if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
166 ConioDeleteConsole(&Console->Header);
167 //CloseHandle(ProcessData->ConsoleEvent);
168 //ProcessData->ConsoleEvent = NULL;
169 }
170 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
171 }
172
173 NTSTATUS
174 FASTCALL
175 Win32CsrInsertObject(PCSR_PROCESS ProcessData,
176 PHANDLE Handle,
177 Object_t *Object,
178 DWORD Access,
179 BOOL Inheritable,
180 DWORD ShareMode)
181 {
182 ULONG i;
183 PCSRSS_HANDLE Block;
184
185 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
186
187 for (i = 0; i < ProcessData->HandleTableSize; i++)
188 {
189 if (ProcessData->HandleTable[i].Object == NULL)
190 {
191 break;
192 }
193 }
194 if (i >= ProcessData->HandleTableSize)
195 {
196 Block = RtlAllocateHeap(ConSrvHeap,
197 HEAP_ZERO_MEMORY,
198 (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
199 if (Block == NULL)
200 {
201 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
202 return(STATUS_UNSUCCESSFUL);
203 }
204 RtlCopyMemory(Block,
205 ProcessData->HandleTable,
206 ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
207 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
208 ProcessData->HandleTable = Block;
209 ProcessData->HandleTableSize += 64;
210 }
211 ProcessData->HandleTable[i].Object = Object;
212 ProcessData->HandleTable[i].Access = Access;
213 ProcessData->HandleTable[i].Inheritable = Inheritable;
214 ProcessData->HandleTable[i].ShareMode = ShareMode;
215 Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
216 *Handle = UlongToHandle((i << 2) | 0x3);
217 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
218 return(STATUS_SUCCESS);
219 }
220
221 NTSTATUS
222 WINAPI
223 Win32CsrDuplicateHandleTable(PCSR_PROCESS SourceProcessData,
224 PCSR_PROCESS TargetProcessData)
225 {
226 ULONG i;
227
228 /* Only inherit if the flag was set */
229 if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
230
231 if (TargetProcessData->HandleTableSize)
232 {
233 return STATUS_INVALID_PARAMETER;
234 }
235
236 RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
237
238 /* we are called from CreateProcessData, it isn't necessary to lock the target process data */
239
240 TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
241 HEAP_ZERO_MEMORY,
242 SourceProcessData->HandleTableSize
243 * sizeof(CSRSS_HANDLE));
244 if (TargetProcessData->HandleTable == NULL)
245 {
246 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
247 return(STATUS_UNSUCCESSFUL);
248 }
249 TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
250 for (i = 0; i < SourceProcessData->HandleTableSize; i++)
251 {
252 if (SourceProcessData->HandleTable[i].Object != NULL &&
253 SourceProcessData->HandleTable[i].Inheritable)
254 {
255 TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
256 Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
257 }
258 }
259 RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
260 return(STATUS_SUCCESS);
261 }
262
263 CSR_API(CsrGetHandle)
264 {
265 NTSTATUS Status = STATUS_SUCCESS;
266 PCSRSS_GET_INPUT_HANDLE GetInputHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetInputHandleRequest;
267 PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
268
269 GetInputHandleRequest->Handle = INVALID_HANDLE_VALUE;
270
271 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
272 if (ProcessData->Console)
273 {
274 DWORD DesiredAccess = GetInputHandleRequest->Access;
275 DWORD ShareMode = GetInputHandleRequest->ShareMode;
276
277 PCSRSS_CONSOLE Console = ProcessData->Console;
278 Object_t *Object;
279
280 EnterCriticalSection(&Console->Lock);
281 if (ApiMessage->ApiNumber == ConsolepGetHandleInformation)
282 Object = &Console->ActiveBuffer->Header;
283 else
284 Object = &Console->Header;
285
286 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
287 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
288 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
289 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
290 {
291 DPRINT1("Sharing violation\n");
292 Status = STATUS_SHARING_VIOLATION;
293 }
294 else
295 {
296 Status = Win32CsrInsertObject(ProcessData,
297 &GetInputHandleRequest->Handle,
298 Object,
299 DesiredAccess,
300 GetInputHandleRequest->Inheritable,
301 ShareMode);
302 }
303 LeaveCriticalSection(&Console->Lock);
304 }
305 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
306
307 return Status;
308 }
309
310 // CSR_API(CsrSetHandle) ??
311
312 CSR_API(SrvCloseHandle)
313 {
314 PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
315
316 return Win32CsrReleaseObject(CsrGetClientThread()->Process, CloseHandleRequest->Handle);
317 }
318
319 CSR_API(SrvVerifyConsoleIoHandle)
320 {
321 NTSTATUS Status = STATUS_SUCCESS;
322 PCSRSS_VERIFY_HANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
323 PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
324 ULONG_PTR Index;
325
326 Index = (ULONG_PTR)VerifyHandleRequest->Handle >> 2;
327 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
328 if (Index >= ProcessData->HandleTableSize ||
329 ProcessData->HandleTable[Index].Object == NULL)
330 {
331 DPRINT("CsrVerifyObject failed\n");
332 Status = STATUS_INVALID_HANDLE;
333 }
334 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
335
336 return Status;
337 }
338
339 CSR_API(SrvDuplicateHandle)
340 {
341 ULONG_PTR Index;
342 PCSRSS_HANDLE Entry;
343 DWORD DesiredAccess;
344 PCSRSS_DUPLICATE_HANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
345 PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
346
347 Index = (ULONG_PTR)DuplicateHandleRequest->Handle >> 2;
348 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
349 if (Index >= ProcessData->HandleTableSize
350 || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
351 {
352 DPRINT1("Couldn't dup invalid handle %p\n", DuplicateHandleRequest->Handle);
353 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
354 return STATUS_INVALID_HANDLE;
355 }
356
357 if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
358 {
359 DesiredAccess = Entry->Access;
360 }
361 else
362 {
363 DesiredAccess = DuplicateHandleRequest->Access;
364 /* Make sure the source handle has all the desired flags */
365 if (~Entry->Access & DesiredAccess)
366 {
367 DPRINT1("Handle %p only has access %X; requested %X\n",
368 DuplicateHandleRequest->Handle, Entry->Access, DesiredAccess);
369 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
370 return STATUS_INVALID_PARAMETER;
371 }
372 }
373
374 ApiMessage->Status = Win32CsrInsertObject(ProcessData,
375 &DuplicateHandleRequest->Handle,
376 Entry->Object,
377 DesiredAccess,
378 DuplicateHandleRequest->Inheritable,
379 Entry->ShareMode);
380 if (NT_SUCCESS(ApiMessage->Status)
381 && DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
382 {
383 Win32CsrCloseHandleEntry(Entry);
384 }
385
386 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
387 return ApiMessage->Status;
388 }
389
390 CSR_API(CsrGetInputWaitHandle)
391 {
392 PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
393
394 GetConsoleInputWaitHandle->InputWaitHandle = CsrGetClientThread()->Process->ConsoleEvent;
395 return STATUS_SUCCESS;
396 }
397
398 /* EOF */