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
&& Required
> 0; 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
;
112 /* Leave the inner loop */
118 /* Return whether we found all required privileges */
119 return (Required
== 0);
124 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src
,
125 ULONG PrivilegeCount
,
126 KPROCESSOR_MODE PreviousMode
,
127 PLUID_AND_ATTRIBUTES AllocatedMem
,
128 ULONG AllocatedLength
,
130 BOOLEAN CaptureIfKernel
,
131 PLUID_AND_ATTRIBUTES
*Dest
,
135 NTSTATUS Status
= STATUS_SUCCESS
;
139 if (PrivilegeCount
== 0)
143 return STATUS_SUCCESS
;
146 if (PreviousMode
== KernelMode
&& !CaptureIfKernel
)
149 return STATUS_SUCCESS
;
152 /* FIXME - check PrivilegeCount for a valid number so we don't
153 cause an integer overflow or exhaust system resources! */
155 BufferSize
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
156 *Length
= ROUND_UP(BufferSize
, 4); /* round up to a 4 byte alignment */
158 /* probe the buffer */
159 if (PreviousMode
!= KernelMode
)
167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
169 /* Return the exception code */
170 _SEH2_YIELD(return _SEH2_GetExceptionCode());
175 /* allocate enough memory or check if the provided buffer is
176 large enough to hold the array */
177 if (AllocatedMem
!= NULL
)
179 if (AllocatedLength
< BufferSize
)
181 return STATUS_BUFFER_TOO_SMALL
;
184 *Dest
= AllocatedMem
;
188 *Dest
= ExAllocatePool(PoolType
,
192 return STATUS_INSUFFICIENT_RESOURCES
;
196 /* copy the array to the buffer */
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
205 Status
= _SEH2_GetExceptionCode();
209 if (!NT_SUCCESS(Status
) && AllocatedMem
== NULL
)
219 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege
,
220 KPROCESSOR_MODE PreviousMode
,
221 BOOLEAN CaptureIfKernel
)
225 if (Privilege
!= NULL
&&
226 (PreviousMode
!= KernelMode
|| CaptureIfKernel
))
228 ExFreePool(Privilege
);
232 /* PUBLIC FUNCTIONS ***********************************************************/
239 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState
,
240 IN PPRIVILEGE_SET Privileges
)
242 PAUX_ACCESS_DATA AuxData
;
243 ULONG OldPrivilegeSetSize
;
244 ULONG NewPrivilegeSetSize
;
245 PPRIVILEGE_SET PrivilegeSet
;
249 /* Get the Auxiliary Data */
250 AuxData
= AccessState
->AuxData
;
252 /* Calculate the size of the old privilege set */
253 OldPrivilegeSetSize
= sizeof(PRIVILEGE_SET
) +
254 (AuxData
->PrivilegeSet
->PrivilegeCount
- 1) * sizeof(LUID_AND_ATTRIBUTES
);
256 if (AuxData
->PrivilegeSet
->PrivilegeCount
+
257 Privileges
->PrivilegeCount
> INITIAL_PRIVILEGE_COUNT
)
259 /* Calculate the size of the new privilege set */
260 NewPrivilegeSetSize
= OldPrivilegeSetSize
+
261 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
263 /* Allocate a new privilege set */
264 PrivilegeSet
= ExAllocatePool(PagedPool
, NewPrivilegeSetSize
);
265 if (PrivilegeSet
== NULL
)
266 return STATUS_INSUFFICIENT_RESOURCES
;
268 /* Copy original privileges from the acess state */
269 RtlCopyMemory(PrivilegeSet
,
270 AuxData
->PrivilegeSet
,
271 OldPrivilegeSetSize
);
273 /* Append privileges from the privilege set*/
274 RtlCopyMemory((PVOID
)((ULONG_PTR
)PrivilegeSet
+ OldPrivilegeSetSize
),
275 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
276 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
278 /* Adjust the number of privileges in the new privilege set */
279 PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
281 /* Free the old privilege set if it was allocated */
282 if (AccessState
->PrivilegesAllocated
== TRUE
)
283 ExFreePool(AuxData
->PrivilegeSet
);
285 /* Now we are using an allocated privilege set */
286 AccessState
->PrivilegesAllocated
= TRUE
;
288 /* Assign the new privileges to the access state */
289 AuxData
->PrivilegeSet
= PrivilegeSet
;
293 /* Append privileges */
294 RtlCopyMemory((PVOID
)((ULONG_PTR
)AuxData
->PrivilegeSet
+ OldPrivilegeSetSize
),
295 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
296 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
298 /* Adjust the number of privileges in the target privilege set */
299 AuxData
->PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
302 return STATUS_SUCCESS
;
310 SeFreePrivileges(IN PPRIVILEGE_SET Privileges
)
313 ExFreePool(Privileges
);
321 SePrivilegeCheck(PPRIVILEGE_SET Privileges
,
322 PSECURITY_SUBJECT_CONTEXT SubjectContext
,
323 KPROCESSOR_MODE PreviousMode
)
325 PACCESS_TOKEN Token
= NULL
;
329 if (SubjectContext
->ClientToken
== NULL
)
331 Token
= SubjectContext
->PrimaryToken
;
335 Token
= SubjectContext
->ClientToken
;
336 if (SubjectContext
->ImpersonationLevel
< 2)
342 return SepPrivilegeCheck(Token
,
343 Privileges
->Privilege
,
344 Privileges
->PrivilegeCount
,
354 SeSinglePrivilegeCheck(IN LUID PrivilegeValue
,
355 IN KPROCESSOR_MODE PreviousMode
)
357 SECURITY_SUBJECT_CONTEXT SubjectContext
;
363 SeCaptureSubjectContext(&SubjectContext
);
365 Priv
.PrivilegeCount
= 1;
366 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
367 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
368 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
370 Result
= SePrivilegeCheck(&Priv
,
374 if (PreviousMode
!= KernelMode
)
377 SePrivilegedServiceAuditAlarm(0,
383 SeReleaseSubjectContext(&SubjectContext
);
390 SeCheckPrivilegedObject(IN LUID PrivilegeValue
,
391 IN HANDLE ObjectHandle
,
392 IN ACCESS_MASK DesiredAccess
,
393 IN KPROCESSOR_MODE PreviousMode
)
395 SECURITY_SUBJECT_CONTEXT SubjectContext
;
401 SeCaptureSubjectContext(&SubjectContext
);
403 Priv
.PrivilegeCount
= 1;
404 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
405 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
406 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
408 Result
= SePrivilegeCheck(&Priv
, &SubjectContext
, PreviousMode
);
409 if (PreviousMode
!= KernelMode
)
412 SePrivilegeObjectAuditAlarm(ObjectHandle
,
421 SeReleaseSubjectContext(&SubjectContext
);
426 /* SYSTEM CALLS ***************************************************************/
430 NtPrivilegeCheck(IN HANDLE ClientToken
,
431 IN PPRIVILEGE_SET RequiredPrivileges
,
434 PLUID_AND_ATTRIBUTES Privileges
;
436 ULONG PrivilegeCount
= 0;
437 ULONG PrivilegeControl
= 0;
440 KPROCESSOR_MODE PreviousMode
;
445 PreviousMode
= KeGetPreviousMode();
447 /* probe the buffers */
448 if (PreviousMode
!= KernelMode
)
452 ProbeForWrite(RequiredPrivileges
,
453 FIELD_OFFSET(PRIVILEGE_SET
,
457 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
458 PrivilegeControl
= RequiredPrivileges
->Control
;
460 /* Check PrivilegeCount to avoid an integer overflow! */
461 if (FIELD_OFFSET(PRIVILEGE_SET
,
462 Privilege
[PrivilegeCount
]) /
463 sizeof(RequiredPrivileges
->Privilege
[0]) != PrivilegeCount
)
465 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
468 /* probe all of the array */
469 ProbeForWrite(RequiredPrivileges
,
470 FIELD_OFFSET(PRIVILEGE_SET
,
471 Privilege
[PrivilegeCount
]),
474 ProbeForWriteBoolean(Result
);
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
478 /* Return the exception code */
479 _SEH2_YIELD(return _SEH2_GetExceptionCode());
485 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
486 PrivilegeControl
= RequiredPrivileges
->Control
;
489 /* reference the token and make sure we're
490 not doing an anonymous impersonation */
491 Status
= ObReferenceObjectByHandle(ClientToken
,
497 if (!NT_SUCCESS(Status
))
502 if (Token
->TokenType
== TokenImpersonation
&&
503 Token
->ImpersonationLevel
< SecurityIdentification
)
505 ObDereferenceObject(Token
);
506 return STATUS_BAD_IMPERSONATION_LEVEL
;
509 /* capture the privileges */
510 Status
= SeCaptureLuidAndAttributesArray(RequiredPrivileges
->Privilege
,
519 if (!NT_SUCCESS(Status
))
521 ObDereferenceObject (Token
);
525 CheckResult
= SepPrivilegeCheck(Token
,
531 ObDereferenceObject(Token
);
533 /* return the array */
536 RtlCopyMemory(RequiredPrivileges
->Privilege
,
538 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
539 *Result
= CheckResult
;
540 Status
= STATUS_SUCCESS
;
542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
544 Status
= _SEH2_GetExceptionCode();
548 SeReleaseLuidAndAttributesArray(Privileges
,