2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/priv.c
5 * PURPOSE: Security manager
7 * PROGRAMMERS: No programmer listed.
10 /* INCLUDES ******************************************************************/
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitPrivileges)
20 /* GLOBALS ********************************************************************/
22 #define CONST_LUID(x1, x2) {x1, x2}
23 const LUID SeCreateTokenPrivilege
= CONST_LUID(SE_CREATE_TOKEN_PRIVILEGE
, 0);
24 const LUID SeAssignPrimaryTokenPrivilege
= CONST_LUID(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, 0);
25 const LUID SeLockMemoryPrivilege
= CONST_LUID(SE_LOCK_MEMORY_PRIVILEGE
, 0);
26 const LUID SeIncreaseQuotaPrivilege
= CONST_LUID(SE_INCREASE_QUOTA_PRIVILEGE
, 0);
27 const LUID SeUnsolicitedInputPrivilege
= CONST_LUID(6, 0);
28 const LUID SeTcbPrivilege
= CONST_LUID(SE_TCB_PRIVILEGE
, 0);
29 const LUID SeSecurityPrivilege
= CONST_LUID(SE_SECURITY_PRIVILEGE
, 0);
30 const LUID SeTakeOwnershipPrivilege
= CONST_LUID(SE_TAKE_OWNERSHIP_PRIVILEGE
, 0);
31 const LUID SeLoadDriverPrivilege
= CONST_LUID(SE_LOAD_DRIVER_PRIVILEGE
, 0);
32 const LUID SeSystemProfilePrivilege
= CONST_LUID(SE_SYSTEM_PROFILE_PRIVILEGE
, 0);
33 const LUID SeSystemtimePrivilege
= CONST_LUID(SE_SYSTEMTIME_PRIVILEGE
, 0);
34 const LUID SeProfileSingleProcessPrivilege
= CONST_LUID(SE_PROF_SINGLE_PROCESS_PRIVILEGE
, 0);
35 const LUID SeIncreaseBasePriorityPrivilege
= CONST_LUID(SE_INC_BASE_PRIORITY_PRIVILEGE
, 0);
36 const LUID SeCreatePagefilePrivilege
= CONST_LUID(SE_CREATE_PAGEFILE_PRIVILEGE
, 0);
37 const LUID SeCreatePermanentPrivilege
= CONST_LUID(SE_CREATE_PERMANENT_PRIVILEGE
, 0);
38 const LUID SeBackupPrivilege
= CONST_LUID(SE_BACKUP_PRIVILEGE
, 0);
39 const LUID SeRestorePrivilege
= CONST_LUID(SE_RESTORE_PRIVILEGE
, 0);
40 const LUID SeShutdownPrivilege
= CONST_LUID(SE_SHUTDOWN_PRIVILEGE
, 0);
41 const LUID SeDebugPrivilege
= CONST_LUID(SE_DEBUG_PRIVILEGE
, 0);
42 const LUID SeAuditPrivilege
= CONST_LUID(SE_AUDIT_PRIVILEGE
, 0);
43 const LUID SeSystemEnvironmentPrivilege
= CONST_LUID(SE_SYSTEM_ENVIRONMENT_PRIVILEGE
, 0);
44 const LUID SeChangeNotifyPrivilege
= CONST_LUID(SE_CHANGE_NOTIFY_PRIVILEGE
, 0);
45 const LUID SeRemoteShutdownPrivilege
= CONST_LUID(SE_REMOTE_SHUTDOWN_PRIVILEGE
, 0);
46 const LUID SeUndockPrivilege
= CONST_LUID(SE_UNDOCK_PRIVILEGE
, 0);
47 const LUID SeSyncAgentPrivilege
= CONST_LUID(SE_SYNC_AGENT_PRIVILEGE
, 0);
48 const LUID SeEnableDelegationPrivilege
= CONST_LUID(SE_ENABLE_DELEGATION_PRIVILEGE
, 0);
49 const LUID SeManageVolumePrivilege
= CONST_LUID(SE_MANAGE_VOLUME_PRIVILEGE
, 0);
50 const LUID SeImpersonatePrivilege
= CONST_LUID(SE_IMPERSONATE_PRIVILEGE
, 0);
51 const LUID SeCreateGlobalPrivilege
= CONST_LUID(SE_CREATE_GLOBAL_PRIVILEGE
, 0);
52 const LUID SeTrustedCredmanPrivilege
= CONST_LUID(SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE
, 0);
53 const LUID SeRelabelPrivilege
= CONST_LUID(SE_RELABEL_PRIVILEGE
, 0);
54 const LUID SeIncreaseWorkingSetPrivilege
= CONST_LUID(SE_INC_WORKING_SET_PRIVILEGE
, 0);
55 const LUID SeTimeZonePrivilege
= CONST_LUID(SE_TIME_ZONE_PRIVILEGE
, 0);
56 const LUID SeCreateSymbolicLinkPrivilege
= CONST_LUID(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
, 0);
59 /* PRIVATE FUNCTIONS **********************************************************/
64 SepInitPrivileges(VOID
)
72 SepPrivilegeCheck(PTOKEN Token
,
73 PLUID_AND_ATTRIBUTES Privileges
,
75 ULONG PrivilegeControl
,
76 KPROCESSOR_MODE PreviousMode
)
82 DPRINT("SepPrivilegeCheck() called\n");
86 if (PreviousMode
== KernelMode
)
89 /* Get the number of privileges that are required to match */
90 Required
= (PrivilegeControl
& PRIVILEGE_SET_ALL_NECESSARY
) ? PrivilegeCount
: 1;
92 /* Acquire a shared token lock */
93 SepAcquireTokenLockShared(Token
);
95 /* Loop all requested privileges until we found the required ones */
96 for (i
= 0; i
< PrivilegeCount
; i
++)
98 /* Loop the privileges of the token */
99 for (j
= 0; j
< Token
->PrivilegeCount
; j
++)
101 /* Check if the LUIDs match */
102 if (RtlEqualLuid(&Token
->Privileges
[j
].Luid
, &Privileges
[i
].Luid
))
104 DPRINT("Found privilege. Attributes: %lx\n",
105 Token
->Privileges
[j
].Attributes
);
107 /* Check if the privilege is enabled */
108 if (Token
->Privileges
[j
].Attributes
& SE_PRIVILEGE_ENABLED
)
110 Privileges
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
113 /* Check if we have found all privileges */
117 SepReleaseTokenLock(Token
);
122 /* Leave the inner loop */
128 /* Release the token lock */
129 SepReleaseTokenLock(Token
);
131 /* When we reached this point, we did not find all privileges */
132 NT_ASSERT(Required
> 0);
138 SepSinglePrivilegeCheck(
141 KPROCESSOR_MODE PreviousMode
)
143 LUID_AND_ATTRIBUTES Privilege
;
145 ASSERT(!RtlEqualLuid(&PrivilegeValue
, &SeTcbPrivilege
));
147 Privilege
.Luid
= PrivilegeValue
;
148 Privilege
.Attributes
= SE_PRIVILEGE_ENABLED
;
149 return SepPrivilegeCheck(Token
,
152 PRIVILEGE_SET_ALL_NECESSARY
,
158 SePrivilegePolicyCheck(
159 _Inout_ PACCESS_MASK DesiredAccess
,
160 _Inout_ PACCESS_MASK GrantedAccess
,
161 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext
,
163 _Out_opt_ PPRIVILEGE_SET
*OutPrivilegeSet
,
164 _In_ KPROCESSOR_MODE PreviousMode
)
166 SIZE_T PrivilegeSize
;
167 PPRIVILEGE_SET PrivilegeSet
;
168 ULONG PrivilegeCount
= 0, Index
= 0;
169 ACCESS_MASK AccessMask
= 0;
172 /* Check if we have a security subject context */
173 if (SubjectContext
!= NULL
)
175 /* Check if there is a client impersonation token */
176 if (SubjectContext
->ClientToken
!= NULL
)
177 Token
= SubjectContext
->ClientToken
;
179 Token
= SubjectContext
->PrimaryToken
;
182 /* Check if the caller wants ACCESS_SYSTEM_SECURITY access */
183 if (*DesiredAccess
& ACCESS_SYSTEM_SECURITY
)
185 /* Do the privilege check */
186 if (SepSinglePrivilegeCheck(SeSecurityPrivilege
, Token
, PreviousMode
))
188 /* Remember this access flag */
189 AccessMask
|= ACCESS_SYSTEM_SECURITY
;
194 return STATUS_PRIVILEGE_NOT_HELD
;
198 /* Check if the caller wants WRITE_OWNER access */
199 if (*DesiredAccess
& WRITE_OWNER
)
201 /* Do the privilege check */
202 if (SepSinglePrivilegeCheck(SeTakeOwnershipPrivilege
, Token
, PreviousMode
))
204 /* Remember this access flag */
205 AccessMask
|= WRITE_OWNER
;
210 /* Update the access masks */
211 *GrantedAccess
|= AccessMask
;
212 *DesiredAccess
&= ~AccessMask
;
214 /* Does the caller want a privilege set? */
215 if (OutPrivilegeSet
!= NULL
)
217 /* Do we have any privileges to report? */
218 if (PrivilegeCount
> 0)
220 /* Calculate size and allocate the structure */
221 PrivilegeSize
= FIELD_OFFSET(PRIVILEGE_SET
, Privilege
[PrivilegeCount
]);
222 PrivilegeSet
= ExAllocatePoolWithTag(PagedPool
, PrivilegeSize
, 'rPeS');
223 *OutPrivilegeSet
= PrivilegeSet
;
224 if (PrivilegeSet
== NULL
)
226 return STATUS_INSUFFICIENT_RESOURCES
;
229 PrivilegeSet
->PrivilegeCount
= PrivilegeCount
;
230 PrivilegeSet
->Control
= 0;
232 if (AccessMask
& WRITE_OWNER
)
234 PrivilegeSet
->Privilege
[Index
].Luid
= SeTakeOwnershipPrivilege
;
235 PrivilegeSet
->Privilege
[Index
].Attributes
= SE_PRIVILEGE_USED_FOR_ACCESS
;
239 if (AccessMask
& ACCESS_SYSTEM_SECURITY
)
241 PrivilegeSet
->Privilege
[Index
].Luid
= SeSecurityPrivilege
;
242 PrivilegeSet
->Privilege
[Index
].Attributes
= SE_PRIVILEGE_USED_FOR_ACCESS
;
247 /* No privileges, no structure */
248 *OutPrivilegeSet
= NULL
;
252 return STATUS_SUCCESS
;
257 SeCheckAuditPrivilege(
258 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext
,
259 _In_ KPROCESSOR_MODE PreviousMode
)
261 PRIVILEGE_SET PrivilegeSet
;
265 /* Initialize the privilege set with the single privilege */
266 PrivilegeSet
.PrivilegeCount
= 1;
267 PrivilegeSet
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
268 PrivilegeSet
.Privilege
[0].Luid
= SeAuditPrivilege
;
269 PrivilegeSet
.Privilege
[0].Attributes
= 0;
271 /* Check against the primary token! */
272 Result
= SepPrivilegeCheck(SubjectContext
->PrimaryToken
,
273 &PrivilegeSet
.Privilege
[0],
275 PRIVILEGE_SET_ALL_NECESSARY
,
278 if (PreviousMode
!= KernelMode
)
280 SePrivilegedServiceAuditAlarm(NULL
,
291 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src
,
292 ULONG PrivilegeCount
,
293 KPROCESSOR_MODE PreviousMode
,
294 PLUID_AND_ATTRIBUTES AllocatedMem
,
295 ULONG AllocatedLength
,
297 BOOLEAN CaptureIfKernel
,
298 PLUID_AND_ATTRIBUTES
*Dest
,
302 NTSTATUS Status
= STATUS_SUCCESS
;
306 if (PrivilegeCount
== 0)
310 return STATUS_SUCCESS
;
313 if (PreviousMode
== KernelMode
&& !CaptureIfKernel
)
316 return STATUS_SUCCESS
;
319 /* FIXME - check PrivilegeCount for a valid number so we don't
320 cause an integer overflow or exhaust system resources! */
322 BufferSize
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
323 *Length
= ROUND_UP(BufferSize
, 4); /* round up to a 4 byte alignment */
325 /* probe the buffer */
326 if (PreviousMode
!= KernelMode
)
334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
336 /* Return the exception code */
337 _SEH2_YIELD(return _SEH2_GetExceptionCode());
342 /* allocate enough memory or check if the provided buffer is
343 large enough to hold the array */
344 if (AllocatedMem
!= NULL
)
346 if (AllocatedLength
< BufferSize
)
348 return STATUS_BUFFER_TOO_SMALL
;
351 *Dest
= AllocatedMem
;
355 *Dest
= ExAllocatePool(PoolType
,
359 return STATUS_INSUFFICIENT_RESOURCES
;
363 /* copy the array to the buffer */
370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
372 Status
= _SEH2_GetExceptionCode();
376 if (!NT_SUCCESS(Status
) && AllocatedMem
== NULL
)
386 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege
,
387 KPROCESSOR_MODE PreviousMode
,
388 BOOLEAN CaptureIfKernel
)
392 if (Privilege
!= NULL
&&
393 (PreviousMode
!= KernelMode
|| CaptureIfKernel
))
395 ExFreePool(Privilege
);
399 /* PUBLIC FUNCTIONS ***********************************************************/
406 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState
,
407 IN PPRIVILEGE_SET Privileges
)
409 PAUX_ACCESS_DATA AuxData
;
410 ULONG OldPrivilegeSetSize
;
411 ULONG NewPrivilegeSetSize
;
412 PPRIVILEGE_SET PrivilegeSet
;
416 /* Get the Auxiliary Data */
417 AuxData
= AccessState
->AuxData
;
419 /* Calculate the size of the old privilege set */
420 OldPrivilegeSetSize
= sizeof(PRIVILEGE_SET
) +
421 (AuxData
->PrivilegeSet
->PrivilegeCount
- 1) * sizeof(LUID_AND_ATTRIBUTES
);
423 if (AuxData
->PrivilegeSet
->PrivilegeCount
+
424 Privileges
->PrivilegeCount
> INITIAL_PRIVILEGE_COUNT
)
426 /* Calculate the size of the new privilege set */
427 NewPrivilegeSetSize
= OldPrivilegeSetSize
+
428 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
430 /* Allocate a new privilege set */
431 PrivilegeSet
= ExAllocatePool(PagedPool
, NewPrivilegeSetSize
);
432 if (PrivilegeSet
== NULL
)
433 return STATUS_INSUFFICIENT_RESOURCES
;
435 /* Copy original privileges from the acess state */
436 RtlCopyMemory(PrivilegeSet
,
437 AuxData
->PrivilegeSet
,
438 OldPrivilegeSetSize
);
440 /* Append privileges from the privilege set*/
441 RtlCopyMemory((PVOID
)((ULONG_PTR
)PrivilegeSet
+ OldPrivilegeSetSize
),
442 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
443 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
445 /* Adjust the number of privileges in the new privilege set */
446 PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
448 /* Free the old privilege set if it was allocated */
449 if (AccessState
->PrivilegesAllocated
== TRUE
)
450 ExFreePool(AuxData
->PrivilegeSet
);
452 /* Now we are using an allocated privilege set */
453 AccessState
->PrivilegesAllocated
= TRUE
;
455 /* Assign the new privileges to the access state */
456 AuxData
->PrivilegeSet
= PrivilegeSet
;
460 /* Append privileges */
461 RtlCopyMemory((PVOID
)((ULONG_PTR
)AuxData
->PrivilegeSet
+ OldPrivilegeSetSize
),
462 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
463 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
465 /* Adjust the number of privileges in the target privilege set */
466 AuxData
->PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
469 return STATUS_SUCCESS
;
477 SeFreePrivileges(IN PPRIVILEGE_SET Privileges
)
480 ExFreePool(Privileges
);
488 SePrivilegeCheck(PPRIVILEGE_SET Privileges
,
489 PSECURITY_SUBJECT_CONTEXT SubjectContext
,
490 KPROCESSOR_MODE PreviousMode
)
492 PACCESS_TOKEN Token
= NULL
;
496 if (SubjectContext
->ClientToken
== NULL
)
498 Token
= SubjectContext
->PrimaryToken
;
502 Token
= SubjectContext
->ClientToken
;
503 if (SubjectContext
->ImpersonationLevel
< 2)
509 return SepPrivilegeCheck(Token
,
510 Privileges
->Privilege
,
511 Privileges
->PrivilegeCount
,
521 SeSinglePrivilegeCheck(IN LUID PrivilegeValue
,
522 IN KPROCESSOR_MODE PreviousMode
)
524 SECURITY_SUBJECT_CONTEXT SubjectContext
;
530 SeCaptureSubjectContext(&SubjectContext
);
532 Priv
.PrivilegeCount
= 1;
533 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
534 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
535 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
537 Result
= SePrivilegeCheck(&Priv
,
541 if (PreviousMode
!= KernelMode
)
543 SePrivilegedServiceAuditAlarm(NULL
,
550 SeReleaseSubjectContext(&SubjectContext
);
557 SeCheckPrivilegedObject(IN LUID PrivilegeValue
,
558 IN HANDLE ObjectHandle
,
559 IN ACCESS_MASK DesiredAccess
,
560 IN KPROCESSOR_MODE PreviousMode
)
562 SECURITY_SUBJECT_CONTEXT SubjectContext
;
568 SeCaptureSubjectContext(&SubjectContext
);
570 Priv
.PrivilegeCount
= 1;
571 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
572 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
573 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
575 Result
= SePrivilegeCheck(&Priv
, &SubjectContext
, PreviousMode
);
576 if (PreviousMode
!= KernelMode
)
579 SePrivilegeObjectAuditAlarm(ObjectHandle
,
588 SeReleaseSubjectContext(&SubjectContext
);
593 /* SYSTEM CALLS ***************************************************************/
597 NtPrivilegeCheck(IN HANDLE ClientToken
,
598 IN PPRIVILEGE_SET RequiredPrivileges
,
601 PLUID_AND_ATTRIBUTES Privileges
;
603 ULONG PrivilegeCount
= 0;
604 ULONG PrivilegeControl
= 0;
607 KPROCESSOR_MODE PreviousMode
;
612 PreviousMode
= KeGetPreviousMode();
614 /* probe the buffers */
615 if (PreviousMode
!= KernelMode
)
619 ProbeForWrite(RequiredPrivileges
,
620 FIELD_OFFSET(PRIVILEGE_SET
,
624 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
625 PrivilegeControl
= RequiredPrivileges
->Control
;
627 /* Check PrivilegeCount to avoid an integer overflow! */
628 if (FIELD_OFFSET(PRIVILEGE_SET
,
629 Privilege
[PrivilegeCount
]) /
630 sizeof(RequiredPrivileges
->Privilege
[0]) != PrivilegeCount
)
632 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
635 /* probe all of the array */
636 ProbeForWrite(RequiredPrivileges
,
637 FIELD_OFFSET(PRIVILEGE_SET
,
638 Privilege
[PrivilegeCount
]),
641 ProbeForWriteBoolean(Result
);
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
645 /* Return the exception code */
646 _SEH2_YIELD(return _SEH2_GetExceptionCode());
652 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
653 PrivilegeControl
= RequiredPrivileges
->Control
;
656 /* reference the token and make sure we're
657 not doing an anonymous impersonation */
658 Status
= ObReferenceObjectByHandle(ClientToken
,
664 if (!NT_SUCCESS(Status
))
669 if (Token
->TokenType
== TokenImpersonation
&&
670 Token
->ImpersonationLevel
< SecurityIdentification
)
672 ObDereferenceObject(Token
);
673 return STATUS_BAD_IMPERSONATION_LEVEL
;
676 /* capture the privileges */
677 Status
= SeCaptureLuidAndAttributesArray(RequiredPrivileges
->Privilege
,
686 if (!NT_SUCCESS(Status
))
688 ObDereferenceObject (Token
);
692 CheckResult
= SepPrivilegeCheck(Token
,
698 ObDereferenceObject(Token
);
700 /* return the array */
703 RtlCopyMemory(RequiredPrivileges
->Privilege
,
705 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
706 *Result
= CheckResult
;
707 Status
= STATUS_SUCCESS
;
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
711 Status
= _SEH2_GetExceptionCode();
715 SeReleaseLuidAndAttributesArray(Privileges
,