[NTOS:IO] Implement IopAcquireFileObjectLock and use it to fix IopLockFileObject
[reactos.git] / ntoskrnl / ob / obsecure.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obsecure.c
5 * PURPOSE: SRM Interface of the Object Manager
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Eric Kohl
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* PRIVATE FUNCTIONS *********************************************************/
17
18 NTSTATUS
19 NTAPI
20 ObAssignObjectSecurityDescriptor(IN PVOID Object,
21 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
22 IN POOL_TYPE PoolType)
23 {
24 POBJECT_HEADER ObjectHeader;
25 NTSTATUS Status;
26 PSECURITY_DESCRIPTOR NewSd;
27 PEX_FAST_REF FastRef;
28 PAGED_CODE();
29
30 /* Get the object header */
31 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
32 FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor;
33 if (!SecurityDescriptor)
34 {
35 /* Nothing to assign */
36 ExInitializeFastReference(FastRef, NULL);
37 return STATUS_SUCCESS;
38 }
39
40 /* Add it to our internal cache */
41 Status = ObLogSecurityDescriptor(SecurityDescriptor,
42 &NewSd,
43 MAX_FAST_REFS + 1);
44 if (NT_SUCCESS(Status))
45 {
46 /* Free the old copy */
47 ExFreePoolWithTag(SecurityDescriptor, TAG_SD);
48
49 /* Set the new pointer */
50 ASSERT(NewSd);
51 ExInitializeFastReference(FastRef, NewSd);
52 }
53
54 /* Return status */
55 return Status;
56 }
57
58 NTSTATUS
59 NTAPI
60 ObDeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
61 {
62 EX_FAST_REF FastRef;
63 ULONG Count;
64 PSECURITY_DESCRIPTOR OldSecurityDescriptor;
65
66 /* Get the fast reference and capture it */
67 FastRef = *(PEX_FAST_REF)SecurityDescriptor;
68
69 /* Don't free again later */
70 *SecurityDescriptor = NULL;
71
72 /* Get the descriptor and reference count */
73 OldSecurityDescriptor = ExGetObjectFastReference(FastRef);
74 Count = ExGetCountFastReference(FastRef);
75
76 /* Dereference the descriptor */
77 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, Count + 1);
78
79 /* All done */
80 return STATUS_SUCCESS;
81 }
82
83 NTSTATUS
84 NTAPI
85 ObQuerySecurityDescriptorInfo(IN PVOID Object,
86 IN PSECURITY_INFORMATION SecurityInformation,
87 OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
88 IN OUT PULONG Length,
89 IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor)
90 {
91 POBJECT_HEADER ObjectHeader;
92 NTSTATUS Status;
93 PSECURITY_DESCRIPTOR ObjectSd;
94 PAGED_CODE();
95
96 /* Get the object header */
97 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
98
99 /* Get the SD */
100 ObjectSd = ObpReferenceSecurityDescriptor(ObjectHeader);
101
102 /* Query the information */
103 Status = SeQuerySecurityDescriptorInfo(SecurityInformation,
104 SecurityDescriptor,
105 Length,
106 &ObjectSd);
107
108 /* Check if we have an object SD and dereference it, if so */
109 if (ObjectSd) ObDereferenceSecurityDescriptor(ObjectSd, 1);
110
111 /* Return status */
112 return Status;
113 }
114
115 NTSTATUS
116 NTAPI
117 ObSetSecurityDescriptorInfo(IN PVOID Object,
118 IN PSECURITY_INFORMATION SecurityInformation,
119 IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
120 IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
121 IN POOL_TYPE PoolType,
122 IN PGENERIC_MAPPING GenericMapping)
123 {
124 NTSTATUS Status;
125 POBJECT_HEADER ObjectHeader;
126 PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor;
127 PEX_FAST_REF FastRef;
128 EX_FAST_REF OldValue;
129 ULONG Count;
130 PAGED_CODE();
131
132 /* Get the object header */
133 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
134 while (TRUE)
135 {
136 /* Reference the old descriptor */
137 OldDescriptor = ObpReferenceSecurityDescriptor(ObjectHeader);
138 NewDescriptor = OldDescriptor;
139
140 /* Set the SD information */
141 Status = SeSetSecurityDescriptorInfo(Object,
142 SecurityInformation,
143 SecurityDescriptor,
144 &NewDescriptor,
145 PoolType,
146 GenericMapping);
147 if (!NT_SUCCESS(Status))
148 {
149 /* We failed, dereference the old one */
150 if (OldDescriptor) ObDereferenceSecurityDescriptor(OldDescriptor, 1);
151 break;
152 }
153
154 /* Now add this to the cache */
155 Status = ObLogSecurityDescriptor(NewDescriptor,
156 &CachedDescriptor,
157 MAX_FAST_REFS + 1);
158
159 /* Let go of our uncached copy */
160 ExFreePool(NewDescriptor);
161
162 /* Check for success */
163 if (!NT_SUCCESS(Status))
164 {
165 /* We failed, dereference the old one */
166 ObDereferenceSecurityDescriptor(OldDescriptor, 1);
167 break;
168 }
169
170 /* Do the swap */
171 FastRef = (PEX_FAST_REF)OutputSecurityDescriptor;
172 OldValue = ExCompareSwapFastReference(FastRef,
173 CachedDescriptor,
174 OldDescriptor);
175
176 /* Make sure the swap worked */
177 if (ExGetObjectFastReference(OldValue) == OldDescriptor)
178 {
179 /* Flush waiters */
180 ObpAcquireObjectLock(ObjectHeader);
181 ObpReleaseObjectLock(ObjectHeader);
182
183 /* And dereference the old one */
184 Count = ExGetCountFastReference(OldValue);
185 ObDereferenceSecurityDescriptor(OldDescriptor, Count + 2);
186 break;
187 }
188 else
189 {
190 /* Someone changed it behind our back -- try again */
191 ObDereferenceSecurityDescriptor(OldDescriptor, 1);
192 ObDereferenceSecurityDescriptor(CachedDescriptor,
193 MAX_FAST_REFS + 1);
194 }
195 }
196
197 /* Return status */
198 return Status;
199 }
200
201 BOOLEAN
202 NTAPI
203 ObCheckCreateObjectAccess(IN PVOID Object,
204 IN ACCESS_MASK CreateAccess,
205 IN PACCESS_STATE AccessState,
206 IN PUNICODE_STRING ComponentName,
207 IN BOOLEAN LockHeld,
208 IN KPROCESSOR_MODE AccessMode,
209 OUT PNTSTATUS AccessStatus)
210 {
211 POBJECT_HEADER ObjectHeader;
212 POBJECT_TYPE ObjectType;
213 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
214 BOOLEAN SdAllocated;
215 BOOLEAN Result = TRUE;
216 ACCESS_MASK GrantedAccess = 0;
217 PPRIVILEGE_SET Privileges = NULL;
218 NTSTATUS Status;
219 PAGED_CODE();
220
221 /* Get the header and type */
222 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
223 ObjectType = ObjectHeader->Type;
224
225 /* Get the security descriptor */
226 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
227 if (!NT_SUCCESS(Status))
228 {
229 /* We failed */
230 *AccessStatus = Status;
231 return FALSE;
232 }
233
234 /* Lock the security context */
235 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
236
237 /* Check if we have an SD */
238 if (SecurityDescriptor)
239 {
240 /* Now do the entire access check */
241 Result = SeAccessCheck(SecurityDescriptor,
242 &AccessState->SubjectSecurityContext,
243 TRUE,
244 CreateAccess,
245 0,
246 &Privileges,
247 &ObjectType->TypeInfo.GenericMapping,
248 AccessMode,
249 &GrantedAccess,
250 AccessStatus);
251 if (Privileges)
252 {
253 /* We got privileges, append them to the access state and free them */
254 Status = SeAppendPrivileges(AccessState, Privileges);
255 SeFreePrivileges(Privileges);
256 }
257 }
258
259 /* We're done, unlock the context and release security */
260 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
261 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
262 return Result;
263 }
264
265 BOOLEAN
266 NTAPI
267 ObpCheckTraverseAccess(IN PVOID Object,
268 IN ACCESS_MASK TraverseAccess,
269 IN PACCESS_STATE AccessState OPTIONAL,
270 IN BOOLEAN LockHeld,
271 IN KPROCESSOR_MODE AccessMode,
272 OUT PNTSTATUS AccessStatus)
273 {
274 POBJECT_HEADER ObjectHeader;
275 POBJECT_TYPE ObjectType;
276 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
277 BOOLEAN SdAllocated;
278 BOOLEAN Result;
279 ACCESS_MASK GrantedAccess = 0;
280 PPRIVILEGE_SET Privileges = NULL;
281 NTSTATUS Status;
282 PAGED_CODE();
283
284 /* Get the header and type */
285 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
286 ObjectType = ObjectHeader->Type;
287
288 /* Get the security descriptor */
289 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
290 if (!NT_SUCCESS(Status))
291 {
292 /* We failed */
293 *AccessStatus = Status;
294 return FALSE;
295 }
296
297 /* First try to perform a fast traverse check
298 * If it fails, then the entire access check will
299 * have to be done.
300 */
301 Result = SeFastTraverseCheck(SecurityDescriptor,
302 AccessState,
303 FILE_WRITE_DATA,
304 AccessMode);
305 if (Result)
306 {
307 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
308 return TRUE;
309 }
310
311 /* Lock the security context */
312 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
313
314 /* Now do the entire access check */
315 Result = SeAccessCheck(SecurityDescriptor,
316 &AccessState->SubjectSecurityContext,
317 TRUE,
318 TraverseAccess,
319 0,
320 &Privileges,
321 &ObjectType->TypeInfo.GenericMapping,
322 AccessMode,
323 &GrantedAccess,
324 AccessStatus);
325 if (Privileges)
326 {
327 /* We got privileges, append them to the access state and free them */
328 Status = SeAppendPrivileges(AccessState, Privileges);
329 SeFreePrivileges(Privileges);
330 }
331
332 /* We're done, unlock the context and release security */
333 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
334 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
335 return Result;
336 }
337
338 BOOLEAN
339 NTAPI
340 ObpCheckObjectReference(IN PVOID Object,
341 IN OUT PACCESS_STATE AccessState,
342 IN BOOLEAN LockHeld,
343 IN KPROCESSOR_MODE AccessMode,
344 OUT PNTSTATUS AccessStatus)
345 {
346 POBJECT_HEADER ObjectHeader;
347 POBJECT_TYPE ObjectType;
348 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
349 BOOLEAN SdAllocated;
350 BOOLEAN Result;
351 ACCESS_MASK GrantedAccess = 0;
352 PPRIVILEGE_SET Privileges = NULL;
353 NTSTATUS Status;
354 PAGED_CODE();
355
356 /* Get the header and type */
357 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
358 ObjectType = ObjectHeader->Type;
359
360 /* Get the security descriptor */
361 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
362 if (!NT_SUCCESS(Status))
363 {
364 /* We failed */
365 *AccessStatus = Status;
366 return FALSE;
367 }
368
369 /* Lock the security context */
370 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
371
372 /* Now do the entire access check */
373 Result = SeAccessCheck(SecurityDescriptor,
374 &AccessState->SubjectSecurityContext,
375 TRUE,
376 AccessState->RemainingDesiredAccess,
377 AccessState->PreviouslyGrantedAccess,
378 &Privileges,
379 &ObjectType->TypeInfo.GenericMapping,
380 AccessMode,
381 &GrantedAccess,
382 AccessStatus);
383 if (Result)
384 {
385 /* Update the access state */
386 AccessState->RemainingDesiredAccess &= ~GrantedAccess;
387 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
388 }
389
390 /* Check if we have an SD */
391 if (SecurityDescriptor)
392 {
393 /* Do audit alarm */
394 #if 0
395 SeObjectReferenceAuditAlarm(&AccessState->OperationID,
396 Object,
397 SecurityDescriptor,
398 &AccessState->SubjectSecurityContext,
399 AccessState->RemainingDesiredAccess |
400 AccessState->PreviouslyGrantedAccess,
401 ((PAUX_ACCESS_DATA)(AccessState->AuxData))->
402 PrivilegeSet,
403 Result,
404 AccessMode);
405 #endif
406 }
407
408 /* We're done, unlock the context and release security */
409 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
410 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
411 return Result;
412 }
413
414 /*++
415 * @name ObCheckObjectAccess
416 *
417 * The ObCheckObjectAccess routine <FILLMEIN>
418 *
419 * @param Object
420 * <FILLMEIN>
421 *
422 * @param AccessState
423 * <FILLMEIN>
424 *
425 * @param LockHeld
426 * <FILLMEIN>
427 *
428 * @param AccessMode
429 * <FILLMEIN>
430 *
431 * @param ReturnedStatus
432 * <FILLMEIN>
433 *
434 * @return TRUE if access was granted, FALSE otherwise.
435 *
436 * @remarks None.
437 *
438 *--*/
439 BOOLEAN
440 NTAPI
441 ObCheckObjectAccess(IN PVOID Object,
442 IN OUT PACCESS_STATE AccessState,
443 IN BOOLEAN LockHeld,
444 IN KPROCESSOR_MODE AccessMode,
445 OUT PNTSTATUS ReturnedStatus)
446 {
447 POBJECT_HEADER ObjectHeader;
448 POBJECT_TYPE ObjectType;
449 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
450 BOOLEAN SdAllocated;
451 NTSTATUS Status;
452 BOOLEAN Result;
453 ACCESS_MASK GrantedAccess;
454 PPRIVILEGE_SET Privileges = NULL;
455 PAGED_CODE();
456
457 /* Get the object header and type */
458 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
459 ObjectType = ObjectHeader->Type;
460
461 /* Get security information */
462 Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
463 if (!NT_SUCCESS(Status))
464 {
465 /* Return failure */
466 *ReturnedStatus = Status;
467 return FALSE;
468 }
469 else if (!SecurityDescriptor)
470 {
471 /* Otherwise, if we don't actually have an SD, return success */
472 *ReturnedStatus = Status;
473 return TRUE;
474 }
475
476 /* Lock the security context */
477 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
478
479 /* Now do the entire access check */
480 Result = SeAccessCheck(SecurityDescriptor,
481 &AccessState->SubjectSecurityContext,
482 TRUE,
483 AccessState->RemainingDesiredAccess,
484 AccessState->PreviouslyGrantedAccess,
485 &Privileges,
486 &ObjectType->TypeInfo.GenericMapping,
487 AccessMode,
488 &GrantedAccess,
489 ReturnedStatus);
490 if (Privileges)
491 {
492 /* We got privileges, append them to the access state and free them */
493 Status = SeAppendPrivileges(AccessState, Privileges);
494 SeFreePrivileges(Privileges);
495 }
496
497 /* Check if access was granted */
498 if (Result)
499 {
500 /* Update the access state */
501 AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
502 MAXIMUM_ALLOWED);
503 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
504 }
505
506 /* Do audit alarm */
507 SeOpenObjectAuditAlarm(&ObjectType->Name,
508 Object,
509 NULL,
510 SecurityDescriptor,
511 AccessState,
512 FALSE,
513 Result,
514 AccessMode,
515 &AccessState->GenerateOnClose);
516
517 /* We're done, unlock the context and release security */
518 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
519 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
520 return Result;
521 }
522
523 /* PUBLIC FUNCTIONS **********************************************************/
524
525 /*++
526 * @name ObAssignSecurity
527 * @implemented NT4
528 *
529 * The ObAssignSecurity routine <FILLMEIN>
530 *
531 * @param AccessState
532 * <FILLMEIN>
533 *
534 * @param SecurityDescriptor
535 * <FILLMEIN>
536 *
537 * @param Object
538 * <FILLMEIN>
539 *
540 * @param Type
541 * <FILLMEIN>
542 *
543 * @return STATUS_SUCCESS or appropriate error value.
544 *
545 * @remarks None.
546 *
547 *--*/
548 NTSTATUS
549 NTAPI
550 ObAssignSecurity(IN PACCESS_STATE AccessState,
551 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
552 IN PVOID Object,
553 IN POBJECT_TYPE Type)
554 {
555 PSECURITY_DESCRIPTOR NewDescriptor;
556 NTSTATUS Status;
557 KIRQL CalloutIrql;
558 PAGED_CODE();
559
560 /* Build the new security descriptor */
561 Status = SeAssignSecurity(SecurityDescriptor,
562 AccessState->SecurityDescriptor,
563 &NewDescriptor,
564 (Type == ObpDirectoryObjectType),
565 &AccessState->SubjectSecurityContext,
566 &Type->TypeInfo.GenericMapping,
567 PagedPool);
568 if (!NT_SUCCESS(Status)) return Status;
569
570 /* Call the security method */
571 ObpCalloutStart(&CalloutIrql);
572 Status = Type->TypeInfo.SecurityProcedure(Object,
573 AssignSecurityDescriptor,
574 NULL,
575 NewDescriptor,
576 NULL,
577 NULL,
578 PagedPool,
579 &Type->TypeInfo.GenericMapping);
580 ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
581
582 /* Check for failure and deassign security if so */
583 if (!NT_SUCCESS(Status)) SeDeassignSecurity(&NewDescriptor);
584
585 /* Return to caller */
586 return Status;
587 }
588
589 /*++
590 * @name ObGetObjectSecurity
591 * @implemented NT4
592 *
593 * The ObGetObjectSecurity routine <FILLMEIN>
594 *
595 * @param Object
596 * <FILLMEIN>
597 *
598 * @param SecurityDescriptor
599 * <FILLMEIN>
600 *
601 * @param MemoryAllocated
602 * <FILLMEIN>
603 *
604 * @return STATUS_SUCCESS or appropriate error value.
605 *
606 * @remarks None.
607 *
608 *--*/
609 NTSTATUS
610 NTAPI
611 ObGetObjectSecurity(IN PVOID Object,
612 OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
613 OUT PBOOLEAN MemoryAllocated)
614 {
615 POBJECT_HEADER Header;
616 POBJECT_TYPE Type;
617 ULONG Length = 0;
618 NTSTATUS Status;
619 SECURITY_INFORMATION SecurityInformation;
620 KIRQL CalloutIrql;
621 PAGED_CODE();
622
623 /* Get the object header and type */
624 Header = OBJECT_TO_OBJECT_HEADER(Object);
625 Type = Header->Type;
626
627 /* Tell the caller that we didn't have to allocate anything yet */
628 *MemoryAllocated = FALSE;
629
630 /* Check if the object uses default security */
631 if (Type->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
632 {
633 /* Reference the descriptor */
634 *SecurityDescriptor = ObpReferenceSecurityDescriptor(Header);
635 return STATUS_SUCCESS;
636 }
637
638 /* Set mask to query */
639 SecurityInformation = OWNER_SECURITY_INFORMATION |
640 GROUP_SECURITY_INFORMATION |
641 DACL_SECURITY_INFORMATION |
642 SACL_SECURITY_INFORMATION;
643
644 /* Get the security descriptor size */
645 ObpCalloutStart(&CalloutIrql);
646 Status = Type->TypeInfo.SecurityProcedure(Object,
647 QuerySecurityDescriptor,
648 &SecurityInformation,
649 *SecurityDescriptor,
650 &Length,
651 &Header->SecurityDescriptor,
652 Type->TypeInfo.PoolType,
653 &Type->TypeInfo.GenericMapping);
654 ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
655
656 /* Check for failure */
657 if (Status != STATUS_BUFFER_TOO_SMALL) return Status;
658
659 /* Allocate security descriptor */
660 *SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
661 Length,
662 TAG_SEC_QUERY);
663 if (!(*SecurityDescriptor)) return STATUS_INSUFFICIENT_RESOURCES;
664 *MemoryAllocated = TRUE;
665
666 /* Query security descriptor */
667 ObpCalloutStart(&CalloutIrql);
668 Status = Type->TypeInfo.SecurityProcedure(Object,
669 QuerySecurityDescriptor,
670 &SecurityInformation,
671 *SecurityDescriptor,
672 &Length,
673 &Header->SecurityDescriptor,
674 Type->TypeInfo.PoolType,
675 &Type->TypeInfo.GenericMapping);
676 ObpCalloutEnd(CalloutIrql, "Security", Type, Object);
677
678 /* Check for failure */
679 if (!NT_SUCCESS(Status))
680 {
681 /* Free the descriptor and tell the caller we failed */
682 ExFreePoolWithTag(*SecurityDescriptor, TAG_SEC_QUERY);
683 *MemoryAllocated = FALSE;
684 }
685
686 /* Return status */
687 return Status;
688 }
689
690 /*++
691 * @name ObReleaseObjectSecurity
692 * @implemented NT4
693 *
694 * The ObReleaseObjectSecurity routine <FILLMEIN>
695 *
696 * @param SecurityDescriptor
697 * <FILLMEIN>
698 *
699 * @param MemoryAllocated
700 * <FILLMEIN>
701 *
702 * @return STATUS_SUCCESS or appropriate error value.
703 *
704 * @remarks None.
705 *
706 *--*/
707 VOID
708 NTAPI
709 ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
710 IN BOOLEAN MemoryAllocated)
711 {
712 PAGED_CODE();
713
714 /* Nothing to do in this case */
715 if (!SecurityDescriptor) return;
716
717 /* Check if we had allocated it from memory */
718 if (MemoryAllocated)
719 {
720 /* Free it */
721 ExFreePool(SecurityDescriptor);
722 }
723 else
724 {
725 /* Otherwise this means we used an internal descriptor */
726 ObDereferenceSecurityDescriptor(SecurityDescriptor, 1);
727 }
728 }
729
730 /*++
731 * @name ObSetSecurityObjectByPointer
732 * @implemented NT5.1
733 *
734 * The ObSetSecurityObjectByPointer routine <FILLMEIN>
735 *
736 * @param SecurityDescriptor
737 * <FILLMEIN>
738 *
739 * @param MemoryAllocated
740 * <FILLMEIN>
741 *
742 * @return STATUS_SUCCESS or appropriate error value.
743 *
744 * @remarks None.
745 *
746 *--*/
747 NTSTATUS
748 NTAPI
749 ObSetSecurityObjectByPointer(IN PVOID Object,
750 IN SECURITY_INFORMATION SecurityInformation,
751 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
752 {
753 POBJECT_TYPE Type;
754 POBJECT_HEADER Header;
755 PAGED_CODE();
756
757 /* Get the header and type */
758 Header = OBJECT_TO_OBJECT_HEADER(Object);
759 Type = Header->Type;
760
761 /* Sanity check */
762 ASSERT(SecurityDescriptor);
763
764 /* Call the security procedure */
765 return Type->TypeInfo.SecurityProcedure(Object,
766 SetSecurityDescriptor,
767 &SecurityInformation,
768 SecurityDescriptor,
769 NULL,
770 &Header->SecurityDescriptor,
771 Type->TypeInfo.PoolType,
772 &Type->TypeInfo.GenericMapping);
773 }
774
775 /*++
776 * @name NtQuerySecurityObject
777 * @implemented NT4
778 *
779 * The NtQuerySecurityObject routine <FILLMEIN>
780 *
781 * @param Handle
782 * <FILLMEIN>
783 *
784 * @param SecurityInformation
785 * <FILLMEIN>
786 *
787 * @param SecurityDescriptor
788 * <FILLMEIN>
789 *
790 * @param Length
791 * <FILLMEIN>
792 *
793 * @param ResultLength
794 * <FILLMEIN>
795 *
796 * @return STATUS_SUCCESS or appropriate error value.
797 *
798 * @remarks None.
799 *
800 *--*/
801 NTSTATUS
802 NTAPI
803 NtQuerySecurityObject(IN HANDLE Handle,
804 IN SECURITY_INFORMATION SecurityInformation,
805 OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
806 IN ULONG Length,
807 OUT PULONG ResultLength)
808 {
809 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
810 PVOID Object;
811 POBJECT_HEADER Header;
812 POBJECT_TYPE Type;
813 ACCESS_MASK DesiredAccess;
814 NTSTATUS Status;
815 PAGED_CODE();
816
817 /* Check if we came from user mode */
818 if (PreviousMode != KernelMode)
819 {
820 /* Enter SEH */
821 _SEH2_TRY
822 {
823 /* Probe the SD and the length pointer */
824 ProbeForWrite(SecurityDescriptor, Length, sizeof(ULONG));
825 ProbeForWriteUlong(ResultLength);
826 }
827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
828 {
829 /* Return the exception code */
830 _SEH2_YIELD(return _SEH2_GetExceptionCode());
831 }
832 _SEH2_END;
833 }
834
835 /* Get the required access rights for the operation */
836 SeQuerySecurityAccessMask(SecurityInformation, &DesiredAccess);
837
838 /* Reference the object */
839 Status = ObReferenceObjectByHandle(Handle,
840 DesiredAccess,
841 NULL,
842 PreviousMode,
843 &Object,
844 NULL);
845 if (!NT_SUCCESS(Status)) return Status;
846
847 /* Get the Object Header and Type */
848 Header = OBJECT_TO_OBJECT_HEADER(Object);
849 Type = Header->Type;
850
851 /* Call the security procedure's query function */
852 Status = Type->TypeInfo.SecurityProcedure(Object,
853 QuerySecurityDescriptor,
854 &SecurityInformation,
855 SecurityDescriptor,
856 &Length,
857 &Header->SecurityDescriptor,
858 Type->TypeInfo.PoolType,
859 &Type->TypeInfo.GenericMapping);
860
861 /* Dereference the object */
862 ObDereferenceObject(Object);
863
864 /* Protect write with SEH */
865 _SEH2_TRY
866 {
867 /* Return the needed length */
868 *ResultLength = Length;
869 }
870 _SEH2_EXCEPT(ExSystemExceptionFilter())
871 {
872 /* Get the exception code */
873 Status = _SEH2_GetExceptionCode();
874 }
875 _SEH2_END;
876
877 /* Return status */
878 return Status;
879 }
880
881 /*++
882 * @name NtSetSecurityObject
883 * @implemented NT4
884 *
885 * The NtSetSecurityObject routine <FILLMEIN>
886 *
887 * @param Handle
888 * <FILLMEIN>
889 *
890 * @param SecurityInformation
891 * <FILLMEIN>
892 *
893 * @param SecurityDescriptor
894 * <FILLMEIN>
895 *
896 * @return STATUS_SUCCESS or appropriate error value.
897 *
898 * @remarks None.
899 *
900 *--*/
901 NTSTATUS
902 NTAPI
903 NtSetSecurityObject(IN HANDLE Handle,
904 IN SECURITY_INFORMATION SecurityInformation,
905 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
906 {
907 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
908 PVOID Object;
909 SECURITY_DESCRIPTOR_RELATIVE *CapturedDescriptor;
910 ACCESS_MASK DesiredAccess = 0;
911 NTSTATUS Status;
912 PAGED_CODE();
913
914 /* Make sure the caller doesn't pass a NULL security descriptor! */
915 if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION;
916
917 /* Set the required access rights for the operation */
918 SeSetSecurityAccessMask(SecurityInformation, &DesiredAccess);
919
920 /* Reference the object */
921 Status = ObReferenceObjectByHandle(Handle,
922 DesiredAccess,
923 NULL,
924 PreviousMode,
925 &Object,
926 NULL);
927 if (NT_SUCCESS(Status))
928 {
929 /* Capture and make a copy of the security descriptor */
930 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
931 PreviousMode,
932 PagedPool,
933 TRUE,
934 (PSECURITY_DESCRIPTOR*)
935 &CapturedDescriptor);
936 if (!NT_SUCCESS(Status))
937 {
938 /* Fail */
939 ObDereferenceObject(Object);
940 return Status;
941 }
942
943 /* Sanity check */
944 ASSERT(CapturedDescriptor->Control & SE_SELF_RELATIVE);
945
946 /*
947 * Make sure the security descriptor passed by the caller
948 * is valid for the operation we're about to perform
949 */
950 if (((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
951 !(CapturedDescriptor->Owner)) ||
952 ((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
953 !(CapturedDescriptor->Group)))
954 {
955 /* Set the failure status */
956 Status = STATUS_INVALID_SECURITY_DESCR;
957 }
958 else
959 {
960 /* Set security */
961 Status = ObSetSecurityObjectByPointer(Object,
962 SecurityInformation,
963 CapturedDescriptor);
964 }
965
966 /* Release the descriptor and return status */
967 SeReleaseSecurityDescriptor((PSECURITY_DESCRIPTOR)CapturedDescriptor,
968 PreviousMode,
969 TRUE);
970
971 /* Now we can dereference the object */
972 ObDereferenceObject(Object);
973 }
974
975 return Status;
976 }
977
978 /*++
979 * @name ObQueryObjectAuditingByHandle
980 * @implemented NT5
981 *
982 * The ObDereferenceSecurityDescriptor routine <FILLMEIN>
983 *
984 * @param SecurityDescriptor
985 * <FILLMEIN>
986 *
987 * @param Count
988 * <FILLMEIN>
989 *
990 * @return STATUS_SUCCESS or appropriate error value.
991 *
992 * @remarks None.
993 *
994 *--*/
995 NTSTATUS
996 NTAPI
997 ObQueryObjectAuditingByHandle(IN HANDLE Handle,
998 OUT PBOOLEAN GenerateOnClose)
999 {
1000 PHANDLE_TABLE_ENTRY HandleEntry;
1001 PVOID HandleTable;
1002 NTSTATUS Status = STATUS_SUCCESS;
1003 PAGED_CODE();
1004
1005 /* Check if we're dealing with a kernel handle */
1006 if (ObpIsKernelHandle(Handle, ExGetPreviousMode()))
1007 {
1008 /* Use the kernel table and convert the handle */
1009 HandleTable = ObpKernelHandleTable;
1010 Handle = ObKernelHandleToHandle(Handle);
1011 }
1012 else
1013 {
1014 /* Use the process's handle table */
1015 HandleTable = PsGetCurrentProcess()->ObjectTable;
1016 }
1017
1018 /* Enter a critical region while we touch the handle table */
1019 KeEnterCriticalRegion();
1020
1021 /* Map the handle */
1022 HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
1023 if(HandleEntry)
1024 {
1025 /* Check if the flag is set */
1026 *GenerateOnClose = HandleEntry->ObAttributes & OBJ_AUDIT_OBJECT_CLOSE;
1027
1028 /* Unlock the entry */
1029 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
1030 }
1031 else
1032 {
1033 /* Otherwise, fail */
1034 Status = STATUS_INVALID_HANDLE;
1035 }
1036
1037 /* Leave the critical region and return the status */
1038 KeLeaveCriticalRegion();
1039 return Status;
1040 }
1041
1042 /* EOF */