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 /* Loop all requested privileges until we found the required ones */
93 for (i
= 0; i
< PrivilegeCount
; i
++)
95 /* Loop the privileges of the token */
96 for (j
= 0; j
< Token
->PrivilegeCount
; j
++)
98 /* Check if the LUIDs match */
99 if (Token
->Privileges
[j
].Luid
.LowPart
== Privileges
[i
].Luid
.LowPart
&&
100 Token
->Privileges
[j
].Luid
.HighPart
== Privileges
[i
].Luid
.HighPart
)
102 DPRINT("Found privilege. Attributes: %lx\n",
103 Token
->Privileges
[j
].Attributes
);
105 /* Check if the privilege is enabled */
106 if (Token
->Privileges
[j
].Attributes
& SE_PRIVILEGE_ENABLED
)
108 Privileges
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
111 /* Check if we have found all privileges */
119 /* Leave the inner loop */
125 /* When we reached this point, we did not find all privileges */
126 NT_ASSERT(Required
> 0);
132 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src
,
133 ULONG PrivilegeCount
,
134 KPROCESSOR_MODE PreviousMode
,
135 PLUID_AND_ATTRIBUTES AllocatedMem
,
136 ULONG AllocatedLength
,
138 BOOLEAN CaptureIfKernel
,
139 PLUID_AND_ATTRIBUTES
*Dest
,
143 NTSTATUS Status
= STATUS_SUCCESS
;
147 if (PrivilegeCount
== 0)
151 return STATUS_SUCCESS
;
154 if (PreviousMode
== KernelMode
&& !CaptureIfKernel
)
157 return STATUS_SUCCESS
;
160 /* FIXME - check PrivilegeCount for a valid number so we don't
161 cause an integer overflow or exhaust system resources! */
163 BufferSize
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
164 *Length
= ROUND_UP(BufferSize
, 4); /* round up to a 4 byte alignment */
166 /* probe the buffer */
167 if (PreviousMode
!= KernelMode
)
175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
177 /* Return the exception code */
178 _SEH2_YIELD(return _SEH2_GetExceptionCode());
183 /* allocate enough memory or check if the provided buffer is
184 large enough to hold the array */
185 if (AllocatedMem
!= NULL
)
187 if (AllocatedLength
< BufferSize
)
189 return STATUS_BUFFER_TOO_SMALL
;
192 *Dest
= AllocatedMem
;
196 *Dest
= ExAllocatePool(PoolType
,
200 return STATUS_INSUFFICIENT_RESOURCES
;
204 /* copy the array to the buffer */
211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
213 Status
= _SEH2_GetExceptionCode();
217 if (!NT_SUCCESS(Status
) && AllocatedMem
== NULL
)
227 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege
,
228 KPROCESSOR_MODE PreviousMode
,
229 BOOLEAN CaptureIfKernel
)
233 if (Privilege
!= NULL
&&
234 (PreviousMode
!= KernelMode
|| CaptureIfKernel
))
236 ExFreePool(Privilege
);
240 /* PUBLIC FUNCTIONS ***********************************************************/
247 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState
,
248 IN PPRIVILEGE_SET Privileges
)
250 PAUX_ACCESS_DATA AuxData
;
251 ULONG OldPrivilegeSetSize
;
252 ULONG NewPrivilegeSetSize
;
253 PPRIVILEGE_SET PrivilegeSet
;
257 /* Get the Auxiliary Data */
258 AuxData
= AccessState
->AuxData
;
260 /* Calculate the size of the old privilege set */
261 OldPrivilegeSetSize
= sizeof(PRIVILEGE_SET
) +
262 (AuxData
->PrivilegeSet
->PrivilegeCount
- 1) * sizeof(LUID_AND_ATTRIBUTES
);
264 if (AuxData
->PrivilegeSet
->PrivilegeCount
+
265 Privileges
->PrivilegeCount
> INITIAL_PRIVILEGE_COUNT
)
267 /* Calculate the size of the new privilege set */
268 NewPrivilegeSetSize
= OldPrivilegeSetSize
+
269 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
271 /* Allocate a new privilege set */
272 PrivilegeSet
= ExAllocatePool(PagedPool
, NewPrivilegeSetSize
);
273 if (PrivilegeSet
== NULL
)
274 return STATUS_INSUFFICIENT_RESOURCES
;
276 /* Copy original privileges from the acess state */
277 RtlCopyMemory(PrivilegeSet
,
278 AuxData
->PrivilegeSet
,
279 OldPrivilegeSetSize
);
281 /* Append privileges from the privilege set*/
282 RtlCopyMemory((PVOID
)((ULONG_PTR
)PrivilegeSet
+ OldPrivilegeSetSize
),
283 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
284 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
286 /* Adjust the number of privileges in the new privilege set */
287 PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
289 /* Free the old privilege set if it was allocated */
290 if (AccessState
->PrivilegesAllocated
== TRUE
)
291 ExFreePool(AuxData
->PrivilegeSet
);
293 /* Now we are using an allocated privilege set */
294 AccessState
->PrivilegesAllocated
= TRUE
;
296 /* Assign the new privileges to the access state */
297 AuxData
->PrivilegeSet
= PrivilegeSet
;
301 /* Append privileges */
302 RtlCopyMemory((PVOID
)((ULONG_PTR
)AuxData
->PrivilegeSet
+ OldPrivilegeSetSize
),
303 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
304 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
306 /* Adjust the number of privileges in the target privilege set */
307 AuxData
->PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
310 return STATUS_SUCCESS
;
318 SeFreePrivileges(IN PPRIVILEGE_SET Privileges
)
321 ExFreePool(Privileges
);
329 SePrivilegeCheck(PPRIVILEGE_SET Privileges
,
330 PSECURITY_SUBJECT_CONTEXT SubjectContext
,
331 KPROCESSOR_MODE PreviousMode
)
333 PACCESS_TOKEN Token
= NULL
;
337 if (SubjectContext
->ClientToken
== NULL
)
339 Token
= SubjectContext
->PrimaryToken
;
343 Token
= SubjectContext
->ClientToken
;
344 if (SubjectContext
->ImpersonationLevel
< 2)
350 return SepPrivilegeCheck(Token
,
351 Privileges
->Privilege
,
352 Privileges
->PrivilegeCount
,
362 SeSinglePrivilegeCheck(IN LUID PrivilegeValue
,
363 IN KPROCESSOR_MODE PreviousMode
)
365 SECURITY_SUBJECT_CONTEXT SubjectContext
;
371 SeCaptureSubjectContext(&SubjectContext
);
373 Priv
.PrivilegeCount
= 1;
374 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
375 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
376 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
378 Result
= SePrivilegeCheck(&Priv
,
382 if (PreviousMode
!= KernelMode
)
385 SePrivilegedServiceAuditAlarm(0,
391 SeReleaseSubjectContext(&SubjectContext
);
398 SeCheckPrivilegedObject(IN LUID PrivilegeValue
,
399 IN HANDLE ObjectHandle
,
400 IN ACCESS_MASK DesiredAccess
,
401 IN KPROCESSOR_MODE PreviousMode
)
403 SECURITY_SUBJECT_CONTEXT SubjectContext
;
409 SeCaptureSubjectContext(&SubjectContext
);
411 Priv
.PrivilegeCount
= 1;
412 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
413 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
414 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
416 Result
= SePrivilegeCheck(&Priv
, &SubjectContext
, PreviousMode
);
417 if (PreviousMode
!= KernelMode
)
420 SePrivilegeObjectAuditAlarm(ObjectHandle
,
429 SeReleaseSubjectContext(&SubjectContext
);
434 /* SYSTEM CALLS ***************************************************************/
438 NtPrivilegeCheck(IN HANDLE ClientToken
,
439 IN PPRIVILEGE_SET RequiredPrivileges
,
442 PLUID_AND_ATTRIBUTES Privileges
;
444 ULONG PrivilegeCount
= 0;
445 ULONG PrivilegeControl
= 0;
448 KPROCESSOR_MODE PreviousMode
;
453 PreviousMode
= KeGetPreviousMode();
455 /* probe the buffers */
456 if (PreviousMode
!= KernelMode
)
460 ProbeForWrite(RequiredPrivileges
,
461 FIELD_OFFSET(PRIVILEGE_SET
,
465 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
466 PrivilegeControl
= RequiredPrivileges
->Control
;
468 /* Check PrivilegeCount to avoid an integer overflow! */
469 if (FIELD_OFFSET(PRIVILEGE_SET
,
470 Privilege
[PrivilegeCount
]) /
471 sizeof(RequiredPrivileges
->Privilege
[0]) != PrivilegeCount
)
473 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
476 /* probe all of the array */
477 ProbeForWrite(RequiredPrivileges
,
478 FIELD_OFFSET(PRIVILEGE_SET
,
479 Privilege
[PrivilegeCount
]),
482 ProbeForWriteBoolean(Result
);
484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
486 /* Return the exception code */
487 _SEH2_YIELD(return _SEH2_GetExceptionCode());
493 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
494 PrivilegeControl
= RequiredPrivileges
->Control
;
497 /* reference the token and make sure we're
498 not doing an anonymous impersonation */
499 Status
= ObReferenceObjectByHandle(ClientToken
,
505 if (!NT_SUCCESS(Status
))
510 if (Token
->TokenType
== TokenImpersonation
&&
511 Token
->ImpersonationLevel
< SecurityIdentification
)
513 ObDereferenceObject(Token
);
514 return STATUS_BAD_IMPERSONATION_LEVEL
;
517 /* capture the privileges */
518 Status
= SeCaptureLuidAndAttributesArray(RequiredPrivileges
->Privilege
,
527 if (!NT_SUCCESS(Status
))
529 ObDereferenceObject (Token
);
533 CheckResult
= SepPrivilegeCheck(Token
,
539 ObDereferenceObject(Token
);
541 /* return the array */
544 RtlCopyMemory(RequiredPrivileges
->Privilege
,
546 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
547 *Result
= CheckResult
;
548 Status
= STATUS_SUCCESS
;
550 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
552 Status
= _SEH2_GetExceptionCode();
556 SeReleaseLuidAndAttributesArray(Privileges
,