xref: /reactos/ntoskrnl/ob/obsecure.c (revision c2c66aff)
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 == ObDirectoryType),
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 */
1043