Added some security functions
[reactos.git] / reactos / ntoskrnl / ob / handle.c
1 /* $Id: handle.c,v 1.17 1999/12/26 15:50:50 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/handle.c
6 * PURPOSE: Managing handles
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * REVISION HISTORY:
9 * 17/06/98: Created
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <string.h>
17 #include <internal/string.h>
18 #include <internal/ps.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* TYPES *******************************************************************/
24
25 #define HANDLE_BLOCK_ENTRIES ((PAGESIZE-sizeof(LIST_ENTRY))/sizeof(HANDLE_REP))
26
27 /*
28 * PURPOSE: Defines a page's worth of handles
29 */
30 typedef struct
31 {
32 LIST_ENTRY entry;
33 HANDLE_REP handles[HANDLE_BLOCK_ENTRIES];
34 } HANDLE_BLOCK, *PHANDLE_BLOCK;
35
36 /* FUNCTIONS ***************************************************************/
37
38
39 static PHANDLE_REP ObpGetObjectByHandle(PHANDLE_TABLE HandleTable, HANDLE h)
40 /*
41 * FUNCTION: Get the data structure for a handle
42 * ARGUMENTS:
43 * Process = Process to get the handle for
44 * h = Handle
45 * ARGUMENTS: A pointer to the information about the handle on success,
46 * NULL on failure
47 */
48 {
49 PLIST_ENTRY current;
50 unsigned int handle = (((unsigned int)h) - 1) >> 3;
51 unsigned int count=handle/HANDLE_BLOCK_ENTRIES;
52 HANDLE_BLOCK* blk = NULL;
53 unsigned int i;
54
55 DPRINT("ObpGetObjectByHandle(Process %x, h %x)\n",Process,h);
56
57 current = HandleTable->ListHead.Flink;
58 DPRINT("current %x\n",current);
59
60 for (i=0;i<count;i++)
61 {
62 current = current->Flink;
63 if (current == (&(HandleTable->ListHead)))
64 {
65 return(NULL);
66 }
67 }
68
69 blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
70 return(&(blk->handles[handle%HANDLE_BLOCK_ENTRIES]));
71 }
72
73
74 NTSTATUS STDCALL NtDuplicateObject (IN HANDLE SourceProcessHandle,
75 IN PHANDLE SourceHandle,
76 IN HANDLE TargetProcessHandle,
77 OUT PHANDLE TargetHandle,
78 IN ACCESS_MASK DesiredAccess,
79 IN BOOLEAN InheritHandle,
80 ULONG Options)
81 /*
82 * FUNCTION: Copies a handle from one process space to another
83 * ARGUMENTS:
84 * SourceProcessHandle = The source process owning the handle. The
85 * source process should have opened
86 * the SourceHandle with PROCESS_DUP_HANDLE
87 * access.
88 * SourceHandle = The handle to the object.
89 * TargetProcessHandle = The destination process owning the handle
90 * TargetHandle (OUT) = Caller should supply storage for the
91 * duplicated handle.
92 * DesiredAccess = The desired access to the handle.
93 * InheritHandle = Indicates wheter the new handle will be inheritable
94 * or not.
95 * Options = Specifies special actions upon duplicating the handle.
96 * Can be one of the values DUPLICATE_CLOSE_SOURCE |
97 * DUPLICATE_SAME_ACCESS. DUPLICATE_CLOSE_SOURCE specifies
98 * that the source handle should be closed after duplicating.
99 * DUPLICATE_SAME_ACCESS specifies to ignore the
100 * DesiredAccess paramter and just grant the same access to
101 * the new handle.
102 * RETURNS: Status
103 * REMARKS: This function maps to the win32 DuplicateHandle.
104 */
105 {
106 PEPROCESS SourceProcess;
107 PEPROCESS TargetProcess;
108 PHANDLE_REP SourceHandleRep;
109 KIRQL oldIrql;
110 PVOID ObjectBody;
111
112 ASSERT_IRQL(PASSIVE_LEVEL);
113
114 ObReferenceObjectByHandle(SourceProcessHandle,
115 PROCESS_DUP_HANDLE,
116 NULL,
117 UserMode,
118 (PVOID*)&SourceProcess,
119 NULL);
120 ObReferenceObjectByHandle(TargetProcessHandle,
121 PROCESS_DUP_HANDLE,
122 NULL,
123 UserMode,
124 (PVOID*)&TargetProcess,
125 NULL);
126
127 KeAcquireSpinLock(&SourceProcess->Pcb.HandleTable.ListLock, &oldIrql);
128 SourceHandleRep = ObpGetObjectByHandle(&SourceProcess->Pcb.HandleTable,
129 *SourceHandle);
130 if (SourceHandleRep == NULL)
131 {
132 KeReleaseSpinLock(&SourceProcess->Pcb.HandleTable.ListLock, oldIrql);
133 ObDereferenceObject(SourceProcess);
134 ObDereferenceObject(TargetProcess);
135 return(STATUS_INVALID_HANDLE);
136 }
137 ObjectBody = SourceHandleRep->ObjectBody;
138 ObReferenceObjectByPointer(ObjectBody,
139 GENERIC_ALL,
140 NULL,
141 UserMode);
142
143 if (Options & DUPLICATE_SAME_ACCESS)
144 {
145 DesiredAccess = SourceHandleRep->GrantedAccess;
146 }
147
148 KeReleaseSpinLock(&SourceProcess->Pcb.HandleTable.ListLock, oldIrql);
149
150 ObCreateHandle(TargetProcess,
151 ObjectBody,
152 DesiredAccess,
153 InheritHandle,
154 TargetHandle);
155
156 if (Options & DUPLICATE_CLOSE_SOURCE)
157 {
158 ZwClose(*SourceHandle);
159 }
160
161 ObDereferenceObject(TargetProcess);
162 ObDereferenceObject(SourceProcess);
163 ObDereferenceObject(ObjectBody);
164
165 return(STATUS_SUCCESS);
166 }
167
168 VOID ObCloseAllHandles(PEPROCESS Process)
169 {
170 KIRQL oldIrql;
171 PHANDLE_TABLE HandleTable;
172 PLIST_ENTRY current_entry;
173 PHANDLE_BLOCK current;
174 ULONG i;
175 PVOID ObjectBody;
176
177 DPRINT("ObCloseAllHandles(Process %x)\n", Process);
178
179 HandleTable = &Process->Pcb.HandleTable;
180
181 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
182
183 current_entry = HandleTable->ListHead.Flink;
184
185 while (current_entry != &HandleTable->ListHead)
186 {
187 current = CONTAINING_RECORD(current_entry, HANDLE_BLOCK, entry);
188
189 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
190 {
191 ObjectBody = current->handles[i].ObjectBody;
192
193 if (ObjectBody != NULL)
194 {
195 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
196
197 if (Header->ObjectType == PsProcessType ||
198 Header->ObjectType == PsThreadType)
199 {
200 DPRINT("Deleting handle to %x\n", ObjectBody);
201 }
202
203 ObReferenceObjectByPointer(ObjectBody,
204 GENERIC_ALL,
205 NULL,
206 UserMode);
207 Header->HandleCount--;
208 current->handles[i].ObjectBody = NULL;
209
210 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
211
212 if ((Header->ObjectType != NULL) &&
213 (Header->ObjectType->Close != NULL))
214 {
215 Header->ObjectType->Close(ObjectBody,
216 Header->HandleCount);
217 }
218
219 ObDereferenceObject(ObjectBody);
220 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
221 current_entry = &HandleTable->ListHead;
222 break;
223 }
224 }
225
226 current_entry = current_entry->Flink;
227 }
228 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
229 DPRINT("ObCloseAllHandles() finished\n");
230 DPRINT("Type %x\n", BODY_TO_HEADER(Process)->ObjectType);
231 }
232
233 VOID ObDeleteHandleTable(PEPROCESS Process)
234 /*
235 * FUNCTION: Deletes the handle table associated with a process
236 */
237 {
238 PLIST_ENTRY current = NULL;
239 PHANDLE_TABLE HandleTable = NULL;
240
241 ObCloseAllHandles(Process);
242
243 HandleTable = &Process->Pcb.HandleTable;
244 current = RemoveHeadList(&HandleTable->ListHead);
245
246 while (current != &HandleTable->ListHead)
247 {
248 HANDLE_BLOCK* HandleBlock = CONTAINING_RECORD(current,
249 HANDLE_BLOCK,
250 entry);
251 DPRINT("Freeing %x\n", HandleBlock);
252 ExFreePool(HandleBlock);
253
254 current = RemoveHeadList(&HandleTable->ListHead);
255 }
256 }
257
258
259 VOID ObCreateHandleTable(PEPROCESS Parent,
260 BOOLEAN Inherit,
261 PEPROCESS Process)
262 /*
263 * FUNCTION: Creates a handle table for a process
264 * ARGUMENTS:
265 * Parent = Parent process (or NULL if this is the first process)
266 * Inherit = True if the process should inherit its parent's handles
267 * Process = Process whose handle table is to be created
268 */
269 {
270 PHANDLE_TABLE ParentHandleTable;
271 KIRQL oldIrql;
272 PLIST_ENTRY parent_current;
273 ULONG i;
274
275 DPRINT("ObCreateHandleTable(Parent %x, Inherit %d, Process %x)\n",
276 Parent,Inherit,Process);
277
278 InitializeListHead(&(Process->Pcb.HandleTable.ListHead));
279 KeInitializeSpinLock(&(Process->Pcb.HandleTable.ListLock));
280
281 if (Parent != NULL)
282 {
283 ParentHandleTable = &Parent->Pcb.HandleTable;
284
285 KeAcquireSpinLock(&Parent->Pcb.HandleTable.ListLock, &oldIrql);
286
287 parent_current = ParentHandleTable->ListHead.Flink;
288
289 while (parent_current != &ParentHandleTable->ListHead)
290 {
291 HANDLE_BLOCK* current_block = CONTAINING_RECORD(parent_current,
292 HANDLE_BLOCK,
293 entry);
294 HANDLE NewHandle;
295
296 for (i=0; i<HANDLE_BLOCK_ENTRIES; i++)
297 {
298 if (Inherit || current_block->handles[i].Inherit)
299 {
300 ObCreateHandle(Process,
301 current_block->handles[i].ObjectBody,
302 current_block->handles[i].GrantedAccess,
303 current_block->handles[i].Inherit,
304 &NewHandle);
305 }
306 else
307 {
308 ObCreateHandle(Process,
309 NULL,
310 0,
311 current_block->handles[i].Inherit,
312 &NewHandle);
313 }
314 }
315
316 parent_current = parent_current->Flink;
317 }
318
319 KeReleaseSpinLock(&Parent->Pcb.HandleTable.ListLock, oldIrql);
320 }
321 }
322
323
324 PVOID ObDeleteHandle(PEPROCESS Process, HANDLE Handle)
325 {
326 PHANDLE_REP Rep;
327 PVOID ObjectBody;
328 KIRQL oldIrql;
329 PHANDLE_TABLE HandleTable;
330 POBJECT_HEADER Header;
331
332 DPRINT("ObDeleteHandle(Handle %x)\n",Handle);
333
334 HandleTable = &Process->Pcb.HandleTable;
335
336 KeAcquireSpinLock(&HandleTable->ListLock, &oldIrql);
337
338 Rep = ObpGetObjectByHandle(HandleTable, Handle);
339 ObjectBody = Rep->ObjectBody;
340 Header = BODY_TO_HEADER(ObjectBody);
341 BODY_TO_HEADER(ObjectBody)->HandleCount--;
342 ObReferenceObjectByPointer(ObjectBody,
343 GENERIC_ALL,
344 NULL,
345 UserMode);
346 Rep->ObjectBody = NULL;
347
348 KeReleaseSpinLock(&HandleTable->ListLock, oldIrql);
349
350 if ((Header->ObjectType != NULL) &&
351 (Header->ObjectType->Close != NULL))
352 {
353 Header->ObjectType->Close(ObjectBody, Header->HandleCount);
354 }
355
356 DPRINT("Finished ObDeleteHandle()\n");
357 return(ObjectBody);
358 }
359
360
361 NTSTATUS ObCreateHandle(PEPROCESS Process,
362 PVOID ObjectBody,
363 ACCESS_MASK GrantedAccess,
364 BOOLEAN Inherit,
365 PHANDLE HandleReturn)
366 /*
367 * FUNCTION: Add a handle referencing an object
368 * ARGUMENTS:
369 * obj = Object body that the handle should refer to
370 * RETURNS: The created handle
371 * NOTE: THe handle is valid only in the context of the current process
372 */
373 {
374 LIST_ENTRY* current;
375 unsigned int handle=1;
376 unsigned int i;
377 HANDLE_BLOCK* new_blk = NULL;
378 PHANDLE_TABLE HandleTable;
379 KIRQL oldlvl;
380
381 DPRINT("ObCreateHandle(Process %x, obj %x)\n",Process,ObjectBody);
382
383 if (ObjectBody != NULL)
384 {
385 BODY_TO_HEADER(ObjectBody)->HandleCount++;
386 }
387
388 HandleTable = &Process->Pcb.HandleTable;
389
390 KeAcquireSpinLock(&HandleTable->ListLock, &oldlvl);
391 current = HandleTable->ListHead.Flink;
392
393 /*
394 * Scan through the currently allocated handle blocks looking for a free
395 * slot
396 */
397 while (current != (&HandleTable->ListHead))
398 {
399 HANDLE_BLOCK* blk = CONTAINING_RECORD(current,HANDLE_BLOCK,entry);
400
401 DPRINT("Current %x\n",current);
402
403 for (i=0;i<HANDLE_BLOCK_ENTRIES;i++)
404 {
405 DPRINT("Considering slot %d containing %x\n",i,blk->handles[i]);
406 if (blk->handles[i].ObjectBody==NULL)
407 {
408 blk->handles[i].ObjectBody = ObjectBody;
409 blk->handles[i].GrantedAccess = GrantedAccess;
410 blk->handles[i].Inherit = Inherit;
411 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
412 *HandleReturn = (HANDLE)((handle + i) << 3);
413 return(STATUS_SUCCESS);
414 }
415 }
416
417 handle = handle + HANDLE_BLOCK_ENTRIES;
418 current = current->Flink;
419 }
420
421 /*
422 * Add a new handle block to the end of the list
423 */
424 new_blk = (HANDLE_BLOCK *)ExAllocatePool(NonPagedPool,sizeof(HANDLE_BLOCK));
425 memset(new_blk,0,sizeof(HANDLE_BLOCK));
426 InsertTailList(&(Process->Pcb.HandleTable.ListHead),
427 &new_blk->entry);
428 KeReleaseSpinLock(&HandleTable->ListLock, oldlvl);
429 new_blk->handles[0].ObjectBody = ObjectBody;
430 new_blk->handles[0].GrantedAccess = GrantedAccess;
431 new_blk->handles[0].Inherit = Inherit;
432 *HandleReturn = (HANDLE)(handle << 3);
433 return(STATUS_SUCCESS);
434 }
435
436
437 NTSTATUS ObReferenceObjectByHandle(HANDLE Handle,
438 ACCESS_MASK DesiredAccess,
439 POBJECT_TYPE ObjectType,
440 KPROCESSOR_MODE AccessMode,
441 PVOID* Object,
442 POBJECT_HANDLE_INFORMATION
443 HandleInformationPtr)
444 /*
445 * FUNCTION: Increments the reference count for an object and returns a
446 * pointer to its body
447 * ARGUMENTS:
448 * Handle = Handle for the object
449 * DesiredAccess = Desired access to the object
450 * ObjectType
451 * AccessMode
452 * Object (OUT) = Points to the object body on return
453 * HandleInformation (OUT) = Contains information about the handle
454 * on return
455 * RETURNS: Status
456 */
457 {
458 PHANDLE_REP HandleRep;
459 POBJECT_HEADER ObjectHeader;
460 KIRQL oldIrql;
461 PVOID ObjectBody;
462 ACCESS_MASK GrantedAccess;
463
464 ASSERT_IRQL(PASSIVE_LEVEL);
465
466 DPRINT("ObReferenceObjectByHandle(Handle %x, DesiredAccess %x, "
467 "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess,
468 ObjectType,AccessMode,Object);
469
470
471 /*
472 * Handle special handle names
473 */
474 if (Handle == NtCurrentProcess() &&
475 (ObjectType == PsProcessType || ObjectType == NULL))
476 {
477 ObReferenceObjectByPointer(PsGetCurrentProcess(),
478 PROCESS_ALL_ACCESS,
479 PsProcessType,
480 UserMode);
481 *Object = PsGetCurrentProcess();
482 DPRINT("Referencing current process %x\n", PsGetCurrentProcess());
483 return(STATUS_SUCCESS);
484 }
485 else if (Handle == NtCurrentProcess())
486 {
487 CHECKPOINT;
488 return(STATUS_OBJECT_TYPE_MISMATCH);
489 }
490 if (Handle == NtCurrentThread() &&
491 (ObjectType == PsThreadType || ObjectType == NULL))
492 {
493 ObReferenceObjectByPointer(PsGetCurrentThread(),
494 THREAD_ALL_ACCESS,
495 PsThreadType,
496 UserMode);
497 *Object = PsGetCurrentThread();
498 CHECKPOINT;
499 return(STATUS_SUCCESS);
500 }
501 else if (Handle == NtCurrentThread())
502 {
503 CHECKPOINT;
504 return(STATUS_OBJECT_TYPE_MISMATCH);
505 }
506
507 KeAcquireSpinLock(&PsGetCurrentProcess()->Pcb.HandleTable.ListLock,
508 &oldIrql);
509 HandleRep = ObpGetObjectByHandle(&PsGetCurrentProcess()->Pcb.HandleTable,
510 Handle);
511 if (HandleRep == NULL || HandleRep->ObjectBody == NULL)
512 {
513 KeReleaseSpinLock(&PsGetCurrentProcess()->Pcb.HandleTable.ListLock,
514 oldIrql);
515 return(STATUS_INVALID_HANDLE);
516 }
517 ObjectBody = HandleRep->ObjectBody;
518 ObReferenceObjectByPointer(ObjectBody,
519 GENERIC_ALL,
520 NULL,
521 UserMode);
522 GrantedAccess = HandleRep->GrantedAccess;
523 KeReleaseSpinLock(&PsGetCurrentProcess()->Pcb.HandleTable.ListLock,
524 oldIrql);
525
526 ObjectHeader = BODY_TO_HEADER(ObjectBody);
527
528 if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType)
529 {
530 CHECKPOINT;
531 return(STATUS_OBJECT_TYPE_MISMATCH);
532 }
533
534 if (!(GrantedAccess & DesiredAccess) &&
535 !((~GrantedAccess) & DesiredAccess))
536 {
537 CHECKPOINT;
538 return(STATUS_ACCESS_DENIED);
539 }
540
541 *Object = ObjectBody;
542
543 CHECKPOINT;
544 return(STATUS_SUCCESS);
545 }
546
547
548 /**********************************************************************
549 * NAME EXPORTED
550 * NtClose
551 *
552 * DESCRIPTION
553 * Closes a handle reference to an object.
554 *
555 * ARGUMENTS
556 * Handle
557 * Handle to close.
558 *
559 * RETURN VALUE
560 * Status.
561 */
562 NTSTATUS STDCALL NtClose(HANDLE Handle)
563 {
564 PVOID ObjectBody;
565 POBJECT_HEADER Header;
566
567 assert_irql(PASSIVE_LEVEL);
568
569 DPRINT("NtClose(Handle %x)\n",Handle);
570
571 ObjectBody = ObDeleteHandle(PsGetCurrentProcess(), Handle);
572
573 Header = BODY_TO_HEADER(ObjectBody);
574
575 DPRINT("Dereferencing %x\n", ObjectBody);
576 ObDereferenceObject(ObjectBody);
577
578 return STATUS_SUCCESS;
579 }
580
581
582 /* EOF */