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