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