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