2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security privileges support
5 * COPYRIGHT: Copyright Alex Ionescu <alex@relsoft.net>
6 * Copyright Timo Kreuzer <timo.kreuzer@reactos.org>
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS ********************************************************************/
18 #define CONST_LUID(x1, x2) {x1, x2}
19 const LUID SeCreateTokenPrivilege
= CONST_LUID(SE_CREATE_TOKEN_PRIVILEGE
, 0);
20 const LUID SeAssignPrimaryTokenPrivilege
= CONST_LUID(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, 0);
21 const LUID SeLockMemoryPrivilege
= CONST_LUID(SE_LOCK_MEMORY_PRIVILEGE
, 0);
22 const LUID SeIncreaseQuotaPrivilege
= CONST_LUID(SE_INCREASE_QUOTA_PRIVILEGE
, 0);
23 const LUID SeUnsolicitedInputPrivilege
= CONST_LUID(6, 0);
24 const LUID SeTcbPrivilege
= CONST_LUID(SE_TCB_PRIVILEGE
, 0);
25 const LUID SeSecurityPrivilege
= CONST_LUID(SE_SECURITY_PRIVILEGE
, 0);
26 const LUID SeTakeOwnershipPrivilege
= CONST_LUID(SE_TAKE_OWNERSHIP_PRIVILEGE
, 0);
27 const LUID SeLoadDriverPrivilege
= CONST_LUID(SE_LOAD_DRIVER_PRIVILEGE
, 0);
28 const LUID SeSystemProfilePrivilege
= CONST_LUID(SE_SYSTEM_PROFILE_PRIVILEGE
, 0);
29 const LUID SeSystemtimePrivilege
= CONST_LUID(SE_SYSTEMTIME_PRIVILEGE
, 0);
30 const LUID SeProfileSingleProcessPrivilege
= CONST_LUID(SE_PROF_SINGLE_PROCESS_PRIVILEGE
, 0);
31 const LUID SeIncreaseBasePriorityPrivilege
= CONST_LUID(SE_INC_BASE_PRIORITY_PRIVILEGE
, 0);
32 const LUID SeCreatePagefilePrivilege
= CONST_LUID(SE_CREATE_PAGEFILE_PRIVILEGE
, 0);
33 const LUID SeCreatePermanentPrivilege
= CONST_LUID(SE_CREATE_PERMANENT_PRIVILEGE
, 0);
34 const LUID SeBackupPrivilege
= CONST_LUID(SE_BACKUP_PRIVILEGE
, 0);
35 const LUID SeRestorePrivilege
= CONST_LUID(SE_RESTORE_PRIVILEGE
, 0);
36 const LUID SeShutdownPrivilege
= CONST_LUID(SE_SHUTDOWN_PRIVILEGE
, 0);
37 const LUID SeDebugPrivilege
= CONST_LUID(SE_DEBUG_PRIVILEGE
, 0);
38 const LUID SeAuditPrivilege
= CONST_LUID(SE_AUDIT_PRIVILEGE
, 0);
39 const LUID SeSystemEnvironmentPrivilege
= CONST_LUID(SE_SYSTEM_ENVIRONMENT_PRIVILEGE
, 0);
40 const LUID SeChangeNotifyPrivilege
= CONST_LUID(SE_CHANGE_NOTIFY_PRIVILEGE
, 0);
41 const LUID SeRemoteShutdownPrivilege
= CONST_LUID(SE_REMOTE_SHUTDOWN_PRIVILEGE
, 0);
42 const LUID SeUndockPrivilege
= CONST_LUID(SE_UNDOCK_PRIVILEGE
, 0);
43 const LUID SeSyncAgentPrivilege
= CONST_LUID(SE_SYNC_AGENT_PRIVILEGE
, 0);
44 const LUID SeEnableDelegationPrivilege
= CONST_LUID(SE_ENABLE_DELEGATION_PRIVILEGE
, 0);
45 const LUID SeManageVolumePrivilege
= CONST_LUID(SE_MANAGE_VOLUME_PRIVILEGE
, 0);
46 const LUID SeImpersonatePrivilege
= CONST_LUID(SE_IMPERSONATE_PRIVILEGE
, 0);
47 const LUID SeCreateGlobalPrivilege
= CONST_LUID(SE_CREATE_GLOBAL_PRIVILEGE
, 0);
48 const LUID SeTrustedCredmanPrivilege
= CONST_LUID(SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE
, 0);
49 const LUID SeRelabelPrivilege
= CONST_LUID(SE_RELABEL_PRIVILEGE
, 0);
50 const LUID SeIncreaseWorkingSetPrivilege
= CONST_LUID(SE_INC_WORKING_SET_PRIVILEGE
, 0);
51 const LUID SeTimeZonePrivilege
= CONST_LUID(SE_TIME_ZONE_PRIVILEGE
, 0);
52 const LUID SeCreateSymbolicLinkPrivilege
= CONST_LUID(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
, 0);
55 /* PRIVATE FUNCTIONS **********************************************************/
59 * Initializes the privileges during the startup phase of the security
60 * manager module. This function serves as a placeholder as it currently
69 SepInitPrivileges(VOID
)
76 * Checks the privileges pointed by Privileges array argument if they exist and
77 * match with the privileges from an access token.
80 * An access token where privileges are to be checked.
82 * @param[in] Privileges
83 * An array of privileges with attributes used as checking indicator for
86 * @param[in] PrivilegeCount
87 * The total number count of privileges in the array.
89 * @param[in] PrivilegeControl
90 * Privilege control bit mask to determine if we should check all the
91 * privileges based on the number count of privileges or not.
93 * @param[in] PreviousMode
94 * Processor level access mode.
97 * Returns TRUE if the required privileges exist and that they do match.
98 * Otherwise the functions returns FALSE.
104 _In_ PLUID_AND_ATTRIBUTES Privileges
,
105 _In_ ULONG PrivilegeCount
,
106 _In_ ULONG PrivilegeControl
,
107 _In_ KPROCESSOR_MODE PreviousMode
)
113 DPRINT("SepPrivilegeCheck() called\n");
117 if (PreviousMode
== KernelMode
)
120 /* Get the number of privileges that are required to match */
121 Required
= (PrivilegeControl
& PRIVILEGE_SET_ALL_NECESSARY
) ? PrivilegeCount
: 1;
123 /* Acquire a shared token lock */
124 SepAcquireTokenLockShared(Token
);
126 /* Loop all requested privileges until we found the required ones */
127 for (i
= 0; i
< PrivilegeCount
; i
++)
129 /* Loop the privileges of the token */
130 for (j
= 0; j
< Token
->PrivilegeCount
; j
++)
132 /* Check if the LUIDs match */
133 if (RtlEqualLuid(&Token
->Privileges
[j
].Luid
, &Privileges
[i
].Luid
))
135 DPRINT("Found privilege. Attributes: %lx\n",
136 Token
->Privileges
[j
].Attributes
);
138 /* Check if the privilege is enabled */
139 if (Token
->Privileges
[j
].Attributes
& SE_PRIVILEGE_ENABLED
)
141 Privileges
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
144 /* Check if we have found all privileges */
148 SepReleaseTokenLock(Token
);
153 /* Leave the inner loop */
159 /* Release the token lock */
160 SepReleaseTokenLock(Token
);
162 /* When we reached this point, we did not find all privileges */
163 ASSERT(Required
> 0);
169 * Checks only single privilege based upon the privilege pointed by a LUID and
170 * if it matches with the one from an access token.
172 * @param[in] PrivilegeValue
173 * The privilege to be checked.
176 * An access token where its privilege is to be checked against the one
177 * provided by the caller.
179 * @param[in] PreviousMode
180 * Processor level access mode.
183 * Returns TRUE if the required privilege exists and that it matches
184 * with the one from the access token, FALSE otherwise.
188 SepSinglePrivilegeCheck(
189 _In_ LUID PrivilegeValue
,
191 _In_ KPROCESSOR_MODE PreviousMode
)
193 LUID_AND_ATTRIBUTES Privilege
;
195 ASSERT(!RtlEqualLuid(&PrivilegeValue
, &SeTcbPrivilege
));
197 Privilege
.Luid
= PrivilegeValue
;
198 Privilege
.Attributes
= SE_PRIVILEGE_ENABLED
;
199 return SepPrivilegeCheck(Token
,
202 PRIVILEGE_SET_ALL_NECESSARY
,
208 * Checks the security policy and returns a set of privileges
209 * based upon the said security policy context.
211 * @param[in,out] DesiredAccess
212 * The desired access right mask.
214 * @param[in,out] GrantedAccess
215 * The granted access rights masks. The rights are granted depending
216 * on the desired access rights requested by the calling thread.
218 * @param[in] SubjectContext
219 * Security subject context. If the caller supplies one, the access token
220 * supplied by the caller will be assigned to one of client or primary tokens
221 * of the subject context in question.
226 * @param[out] OutPrivilegeSet
227 * An array set of privileges to be reported to the caller, if the actual
228 * calling thread wants such set of privileges in the first place.
230 * @param[in] PreviousMode
231 * Processor level access mode.
234 * Returns STATUS_PRIVILEGE_NOT_HELD if the respective operations have succeeded
235 * without problems. STATUS_PRIVILEGE_NOT_HELD is returned if the access token
236 * doesn't have SeSecurityPrivilege privilege to warrant ACCESS_SYSTEM_SECURITY
237 * access right. STATUS_INSUFFICIENT_RESOURCES is returned if we failed
238 * to allocate block of memory pool for the array set of privileges.
242 SePrivilegePolicyCheck(
243 _Inout_ PACCESS_MASK DesiredAccess
,
244 _Inout_ PACCESS_MASK GrantedAccess
,
245 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext
,
247 _Out_opt_ PPRIVILEGE_SET
*OutPrivilegeSet
,
248 _In_ KPROCESSOR_MODE PreviousMode
)
250 SIZE_T PrivilegeSize
;
251 PPRIVILEGE_SET PrivilegeSet
;
252 ULONG PrivilegeCount
= 0, Index
= 0;
253 ACCESS_MASK AccessMask
= 0;
256 /* Check if we have a security subject context */
257 if (SubjectContext
!= NULL
)
259 /* Check if there is a client impersonation token */
260 if (SubjectContext
->ClientToken
!= NULL
)
261 Token
= SubjectContext
->ClientToken
;
263 Token
= SubjectContext
->PrimaryToken
;
266 /* Check if the caller wants ACCESS_SYSTEM_SECURITY access */
267 if (*DesiredAccess
& ACCESS_SYSTEM_SECURITY
)
269 /* Do the privilege check */
270 if (SepSinglePrivilegeCheck(SeSecurityPrivilege
, Token
, PreviousMode
))
272 /* Remember this access flag */
273 AccessMask
|= ACCESS_SYSTEM_SECURITY
;
278 return STATUS_PRIVILEGE_NOT_HELD
;
282 /* Check if the caller wants WRITE_OWNER access */
283 if (*DesiredAccess
& WRITE_OWNER
)
285 /* Do the privilege check */
286 if (SepSinglePrivilegeCheck(SeTakeOwnershipPrivilege
, Token
, PreviousMode
))
288 /* Remember this access flag */
289 AccessMask
|= WRITE_OWNER
;
294 /* Update the access masks */
295 *GrantedAccess
|= AccessMask
;
296 *DesiredAccess
&= ~AccessMask
;
298 /* Does the caller want a privilege set? */
299 if (OutPrivilegeSet
!= NULL
)
301 /* Do we have any privileges to report? */
302 if (PrivilegeCount
> 0)
304 /* Calculate size and allocate the structure */
305 PrivilegeSize
= FIELD_OFFSET(PRIVILEGE_SET
, Privilege
[PrivilegeCount
]);
306 PrivilegeSet
= ExAllocatePoolWithTag(PagedPool
, PrivilegeSize
, TAG_PRIVILEGE_SET
);
307 *OutPrivilegeSet
= PrivilegeSet
;
308 if (PrivilegeSet
== NULL
)
310 return STATUS_INSUFFICIENT_RESOURCES
;
313 PrivilegeSet
->PrivilegeCount
= PrivilegeCount
;
314 PrivilegeSet
->Control
= 0;
316 if (AccessMask
& WRITE_OWNER
)
318 PrivilegeSet
->Privilege
[Index
].Luid
= SeTakeOwnershipPrivilege
;
319 PrivilegeSet
->Privilege
[Index
].Attributes
= SE_PRIVILEGE_USED_FOR_ACCESS
;
323 if (AccessMask
& ACCESS_SYSTEM_SECURITY
)
325 PrivilegeSet
->Privilege
[Index
].Luid
= SeSecurityPrivilege
;
326 PrivilegeSet
->Privilege
[Index
].Attributes
= SE_PRIVILEGE_USED_FOR_ACCESS
;
331 /* No privileges, no structure */
332 *OutPrivilegeSet
= NULL
;
336 return STATUS_SUCCESS
;
341 * Checks a single privilege and performs an audit
342 * against a privileged service based on a security subject
345 * @param[in] DesiredAccess
346 * Security subject context used for privileged service
349 * @param[in] PreviousMode
350 * Processor level access mode.
353 * Returns TRUE if service auditing and privilege checking
354 * tests have succeeded, FALSE otherwise.
358 SeCheckAuditPrivilege(
359 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext
,
360 _In_ KPROCESSOR_MODE PreviousMode
)
362 PRIVILEGE_SET PrivilegeSet
;
366 /* Initialize the privilege set with the single privilege */
367 PrivilegeSet
.PrivilegeCount
= 1;
368 PrivilegeSet
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
369 PrivilegeSet
.Privilege
[0].Luid
= SeAuditPrivilege
;
370 PrivilegeSet
.Privilege
[0].Attributes
= 0;
372 /* Check against the primary token! */
373 Result
= SepPrivilegeCheck(SubjectContext
->PrimaryToken
,
374 &PrivilegeSet
.Privilege
[0],
376 PRIVILEGE_SET_ALL_NECESSARY
,
379 if (PreviousMode
!= KernelMode
)
381 SePrivilegedServiceAuditAlarm(NULL
,
392 * Captures a LUID with attributes structure. This function is mainly
393 * tied in the context of privileges.
396 * Source of a valid LUID with attributes structure.
398 * @param[in] PrivilegeCount
399 * Count number of privileges to be captured.
401 * @param[in] PreviousMode
402 * Processor level access mode.
404 * @param[in] AllocatedMem
405 * If specified, the function will use this allocated block memory
406 * buffer for the captured LUID and attributes structure. Otherwise
407 * the function will automatically allocate some buffer for it.
409 * @param[in] AllocatedLength
410 * The length of the buffer, pointed by AllocatedMem.
412 * @param[in] PoolType
413 * Pool type of the memory allocation.
415 * @param[in] CaptureIfKernel
416 * If set to TRUE, the capturing is done in the kernel itself.
417 * FALSE if the capturing is done in a kernel mode driver instead.
420 * The captured LUID with attributes buffer.
422 * @param[in,out] Length
423 * The length of the captured privileges count.
426 * Returns STATUS_SUCCESS if the LUID and attributes array
427 * has been captured successfully. STATUS_INSUFFICIENT_RESOURCES is returned
428 * if memory pool allocation for the captured buffer has failed.
429 * STATUS_BUFFER_TOO_SMALL is returned if the buffer size is less than the
434 SeCaptureLuidAndAttributesArray(
435 _In_ PLUID_AND_ATTRIBUTES Src
,
436 _In_ ULONG PrivilegeCount
,
437 _In_ KPROCESSOR_MODE PreviousMode
,
438 _In_opt_ PLUID_AND_ATTRIBUTES AllocatedMem
,
439 _In_opt_ ULONG AllocatedLength
,
440 _In_ POOL_TYPE PoolType
,
441 _In_ BOOLEAN CaptureIfKernel
,
442 _Out_ PLUID_AND_ATTRIBUTES
*Dest
,
443 _Inout_ PULONG Length
)
446 NTSTATUS Status
= STATUS_SUCCESS
;
450 if (PrivilegeCount
== 0)
454 return STATUS_SUCCESS
;
457 if (PreviousMode
== KernelMode
&& !CaptureIfKernel
)
460 return STATUS_SUCCESS
;
463 /* FIXME - check PrivilegeCount for a valid number so we don't
464 cause an integer overflow or exhaust system resources! */
466 BufferSize
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
467 *Length
= ROUND_UP(BufferSize
, 4); /* round up to a 4 byte alignment */
469 /* probe the buffer */
470 if (PreviousMode
!= KernelMode
)
478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
480 /* Return the exception code */
481 _SEH2_YIELD(return _SEH2_GetExceptionCode());
486 /* allocate enough memory or check if the provided buffer is
487 large enough to hold the array */
488 if (AllocatedMem
!= NULL
)
490 if (AllocatedLength
< BufferSize
)
492 return STATUS_BUFFER_TOO_SMALL
;
495 *Dest
= AllocatedMem
;
499 *Dest
= ExAllocatePoolWithTag(PoolType
,
504 return STATUS_INSUFFICIENT_RESOURCES
;
508 /* copy the array to the buffer */
515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
517 Status
= _SEH2_GetExceptionCode();
521 if (!NT_SUCCESS(Status
) && AllocatedMem
== NULL
)
523 ExFreePoolWithTag(*Dest
, TAG_LUID
);
531 * Releases a LUID with attributes structure.
533 * @param[in] Privilege
534 * Array of a LUID and attributes that represents a privilege.
536 * @param[in] PreviousMode
537 * Processor level access mode.
539 * @param[in] CaptureIfKernel
540 * If set to TRUE, the releasing is done in the kernel itself.
541 * FALSE if the releasing is done in a kernel mode driver instead.
548 SeReleaseLuidAndAttributesArray(
549 _In_ PLUID_AND_ATTRIBUTES Privilege
,
550 _In_ KPROCESSOR_MODE PreviousMode
,
551 _In_ BOOLEAN CaptureIfKernel
)
555 if (Privilege
!= NULL
&&
556 (PreviousMode
!= KernelMode
|| CaptureIfKernel
))
558 ExFreePoolWithTag(Privilege
, TAG_LUID
);
562 /* PUBLIC FUNCTIONS ***********************************************************/
566 * Appends additional privileges.
568 * @param[in] AccessState
569 * Access request to append.
571 * @param[in] Privileges
572 * Set of new privileges to append.
575 * Returns STATUS_SUCCESS if the privileges have been successfully
576 * appended. Otherwise STATUS_INSUFFICIENT_RESOURCES is returned,
577 * indicating that pool allocation has failed for the buffer to hold
578 * the new set of privileges.
583 _Inout_ PACCESS_STATE AccessState
,
584 _In_ PPRIVILEGE_SET Privileges
)
586 PAUX_ACCESS_DATA AuxData
;
587 ULONG OldPrivilegeSetSize
;
588 ULONG NewPrivilegeSetSize
;
589 PPRIVILEGE_SET PrivilegeSet
;
593 /* Get the Auxiliary Data */
594 AuxData
= AccessState
->AuxData
;
596 /* Calculate the size of the old privilege set */
597 OldPrivilegeSetSize
= sizeof(PRIVILEGE_SET
) +
598 (AuxData
->PrivilegeSet
->PrivilegeCount
- 1) * sizeof(LUID_AND_ATTRIBUTES
);
600 if (AuxData
->PrivilegeSet
->PrivilegeCount
+
601 Privileges
->PrivilegeCount
> INITIAL_PRIVILEGE_COUNT
)
603 /* Calculate the size of the new privilege set */
604 NewPrivilegeSetSize
= OldPrivilegeSetSize
+
605 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
607 /* Allocate a new privilege set */
608 PrivilegeSet
= ExAllocatePoolWithTag(PagedPool
,
611 if (PrivilegeSet
== NULL
)
612 return STATUS_INSUFFICIENT_RESOURCES
;
614 /* Copy original privileges from the acess state */
615 RtlCopyMemory(PrivilegeSet
,
616 AuxData
->PrivilegeSet
,
617 OldPrivilegeSetSize
);
619 /* Append privileges from the privilege set*/
620 RtlCopyMemory((PVOID
)((ULONG_PTR
)PrivilegeSet
+ OldPrivilegeSetSize
),
621 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
622 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
624 /* Adjust the number of privileges in the new privilege set */
625 PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
627 /* Free the old privilege set if it was allocated */
628 if (AccessState
->PrivilegesAllocated
!= FALSE
)
629 ExFreePoolWithTag(AuxData
->PrivilegeSet
, TAG_PRIVILEGE_SET
);
631 /* Now we are using an allocated privilege set */
632 AccessState
->PrivilegesAllocated
= TRUE
;
634 /* Assign the new privileges to the access state */
635 AuxData
->PrivilegeSet
= PrivilegeSet
;
639 /* Append privileges */
640 RtlCopyMemory((PVOID
)((ULONG_PTR
)AuxData
->PrivilegeSet
+ OldPrivilegeSetSize
),
641 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
642 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
644 /* Adjust the number of privileges in the target privilege set */
645 AuxData
->PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
648 return STATUS_SUCCESS
;
653 * Frees a set of privileges.
655 * @param[in] Privileges
656 * Set of privileges array to be freed.
664 _In_ PPRIVILEGE_SET Privileges
)
667 ExFreePoolWithTag(Privileges
, TAG_PRIVILEGE_SET
);
672 * Checks if a set of privileges exist and match within a
673 * security subject context.
675 * @param[in] Privileges
676 * A set of privileges where the check must be performed
677 * against the subject context.
679 * @param[in] SubjectContext
680 * A subject security context.
682 * @param[in] PreviousMode
683 * Processor level access mode.
686 * Returns TRUE if all the privileges do exist and match
687 * with the ones specified by the caller and subject
688 * context, FALSE otherwise.
693 _In_ PPRIVILEGE_SET Privileges
,
694 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext
,
695 _In_ KPROCESSOR_MODE PreviousMode
)
697 PACCESS_TOKEN Token
= NULL
;
701 if (SubjectContext
->ClientToken
== NULL
)
703 Token
= SubjectContext
->PrimaryToken
;
707 Token
= SubjectContext
->ClientToken
;
708 if (SubjectContext
->ImpersonationLevel
< 2)
714 return SepPrivilegeCheck(Token
,
715 Privileges
->Privilege
,
716 Privileges
->PrivilegeCount
,
723 * Checks if a single privilege is present in the context
724 * of the calling thread.
726 * @param[in] PrivilegeValue
727 * The specific privilege to be checked.
729 * @param[in] PreviousMode
730 * Processor level access mode.
733 * Returns TRUE if the privilege is present, FALSE
738 SeSinglePrivilegeCheck(
739 _In_ LUID PrivilegeValue
,
740 _In_ KPROCESSOR_MODE PreviousMode
)
742 SECURITY_SUBJECT_CONTEXT SubjectContext
;
748 SeCaptureSubjectContext(&SubjectContext
);
750 Priv
.PrivilegeCount
= 1;
751 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
752 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
753 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
755 Result
= SePrivilegeCheck(&Priv
,
759 if (PreviousMode
!= KernelMode
)
761 SePrivilegedServiceAuditAlarm(NULL
,
768 SeReleaseSubjectContext(&SubjectContext
);
775 * Checks a privileged object if such object has
776 * the specific privilege submitted by the caller.
778 * @param[in] PrivilegeValue
779 * A privilege to be checked against the one from
782 * @param[in] ObjectHandle
783 * A handle to any kind of object.
785 * @param[in] DesiredAccess
786 * Desired access right mask requested by the caller.
788 * @param[in] PreviousMode
789 * Processor level access mode.
792 * Returns TRUE if the privilege is present, FALSE
797 SeCheckPrivilegedObject(
798 _In_ LUID PrivilegeValue
,
799 _In_ HANDLE ObjectHandle
,
800 _In_ ACCESS_MASK DesiredAccess
,
801 _In_ KPROCESSOR_MODE PreviousMode
)
803 SECURITY_SUBJECT_CONTEXT SubjectContext
;
809 SeCaptureSubjectContext(&SubjectContext
);
811 Priv
.PrivilegeCount
= 1;
812 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
813 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
814 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
816 Result
= SePrivilegeCheck(&Priv
, &SubjectContext
, PreviousMode
);
817 if (PreviousMode
!= KernelMode
)
820 SePrivilegeObjectAuditAlarm(ObjectHandle
,
829 SeReleaseSubjectContext(&SubjectContext
);
834 /* SYSTEM CALLS ***************************************************************/
838 * Checks a client access token if it has the required set of
841 * @param[in] ClientToken
842 * A handle to an access client token.
844 * @param[in] RequiredPrivileges
845 * A set of required privileges to be checked against the privileges
846 * of the access token.
849 * The result, as a boolean value. If TRUE, the token has all the required
850 * privileges, FALSE otherwise.
853 * Returns STATUS_SUCCESS if the function has completed successfully.
854 * STATUS_INVALID_PARAMETER is returned if the set array of required
855 * privileges has a bogus number of privileges, that is, the array
856 * has a count of privileges that exceeds the maximum threshold
857 * (or in other words, an integer overflow). A failure NTSTATUS code
858 * is returned otherwise.
863 _In_ HANDLE ClientToken
,
864 _In_ PPRIVILEGE_SET RequiredPrivileges
,
865 _Out_ PBOOLEAN Result
)
867 PLUID_AND_ATTRIBUTES Privileges
;
869 ULONG PrivilegeCount
= 0;
870 ULONG PrivilegeControl
= 0;
873 KPROCESSOR_MODE PreviousMode
;
878 PreviousMode
= KeGetPreviousMode();
880 /* probe the buffers */
881 if (PreviousMode
!= KernelMode
)
885 ProbeForWrite(RequiredPrivileges
,
886 FIELD_OFFSET(PRIVILEGE_SET
,
890 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
891 PrivilegeControl
= RequiredPrivileges
->Control
;
893 /* Check PrivilegeCount to avoid an integer overflow! */
894 if (FIELD_OFFSET(PRIVILEGE_SET
,
895 Privilege
[PrivilegeCount
]) /
896 sizeof(RequiredPrivileges
->Privilege
[0]) != PrivilegeCount
)
898 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
901 /* probe all of the array */
902 ProbeForWrite(RequiredPrivileges
,
903 FIELD_OFFSET(PRIVILEGE_SET
,
904 Privilege
[PrivilegeCount
]),
907 ProbeForWriteBoolean(Result
);
909 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
911 /* Return the exception code */
912 _SEH2_YIELD(return _SEH2_GetExceptionCode());
918 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
919 PrivilegeControl
= RequiredPrivileges
->Control
;
922 /* reference the token and make sure we're
923 not doing an anonymous impersonation */
924 Status
= ObReferenceObjectByHandle(ClientToken
,
930 if (!NT_SUCCESS(Status
))
935 if (Token
->TokenType
== TokenImpersonation
&&
936 Token
->ImpersonationLevel
< SecurityIdentification
)
938 ObDereferenceObject(Token
);
939 return STATUS_BAD_IMPERSONATION_LEVEL
;
942 /* capture the privileges */
943 Status
= SeCaptureLuidAndAttributesArray(RequiredPrivileges
->Privilege
,
952 if (!NT_SUCCESS(Status
))
954 ObDereferenceObject (Token
);
958 CheckResult
= SepPrivilegeCheck(Token
,
964 ObDereferenceObject(Token
);
966 /* return the array */
969 RtlCopyMemory(RequiredPrivileges
->Privilege
,
971 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
972 *Result
= CheckResult
;
973 Status
= STATUS_SUCCESS
;
975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
977 Status
= _SEH2_GetExceptionCode();
981 SeReleaseLuidAndAttributesArray(Privileges
,