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 LUID SeCreateTokenPrivilege
;
23 LUID SeAssignPrimaryTokenPrivilege
;
24 LUID SeLockMemoryPrivilege
;
25 LUID SeIncreaseQuotaPrivilege
;
26 LUID SeUnsolicitedInputPrivilege
;
28 LUID SeSecurityPrivilege
;
29 LUID SeTakeOwnershipPrivilege
;
30 LUID SeLoadDriverPrivilege
;
31 LUID SeCreatePagefilePrivilege
;
32 LUID SeIncreaseBasePriorityPrivilege
;
33 LUID SeSystemProfilePrivilege
;
34 LUID SeSystemtimePrivilege
;
35 LUID SeProfileSingleProcessPrivilege
;
36 LUID SeCreatePermanentPrivilege
;
37 LUID SeBackupPrivilege
;
38 LUID SeRestorePrivilege
;
39 LUID SeShutdownPrivilege
;
40 LUID SeDebugPrivilege
;
41 LUID SeAuditPrivilege
;
42 LUID SeSystemEnvironmentPrivilege
;
43 LUID SeChangeNotifyPrivilege
;
44 LUID SeRemoteShutdownPrivilege
;
45 LUID SeUndockPrivilege
;
46 LUID SeSyncAgentPrivilege
;
47 LUID SeEnableDelegationPrivilege
;
49 /* PRIVATE FUNCTIONS **********************************************************/
54 SepInitPrivileges(VOID
)
56 SeCreateTokenPrivilege
.LowPart
= SE_CREATE_TOKEN_PRIVILEGE
;
57 SeCreateTokenPrivilege
.HighPart
= 0;
58 SeAssignPrimaryTokenPrivilege
.LowPart
= SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
;
59 SeAssignPrimaryTokenPrivilege
.HighPart
= 0;
60 SeLockMemoryPrivilege
.LowPart
= SE_LOCK_MEMORY_PRIVILEGE
;
61 SeLockMemoryPrivilege
.HighPart
= 0;
62 SeIncreaseQuotaPrivilege
.LowPart
= SE_INCREASE_QUOTA_PRIVILEGE
;
63 SeIncreaseQuotaPrivilege
.HighPart
= 0;
64 SeUnsolicitedInputPrivilege
.LowPart
= SE_UNSOLICITED_INPUT_PRIVILEGE
;
65 SeUnsolicitedInputPrivilege
.HighPart
= 0;
66 SeTcbPrivilege
.LowPart
= SE_TCB_PRIVILEGE
;
67 SeTcbPrivilege
.HighPart
= 0;
68 SeSecurityPrivilege
.LowPart
= SE_SECURITY_PRIVILEGE
;
69 SeSecurityPrivilege
.HighPart
= 0;
70 SeTakeOwnershipPrivilege
.LowPart
= SE_TAKE_OWNERSHIP_PRIVILEGE
;
71 SeTakeOwnershipPrivilege
.HighPart
= 0;
72 SeLoadDriverPrivilege
.LowPart
= SE_LOAD_DRIVER_PRIVILEGE
;
73 SeLoadDriverPrivilege
.HighPart
= 0;
74 SeSystemProfilePrivilege
.LowPart
= SE_SYSTEM_PROFILE_PRIVILEGE
;
75 SeSystemProfilePrivilege
.HighPart
= 0;
76 SeSystemtimePrivilege
.LowPart
= SE_SYSTEMTIME_PRIVILEGE
;
77 SeSystemtimePrivilege
.HighPart
= 0;
78 SeProfileSingleProcessPrivilege
.LowPart
= SE_PROF_SINGLE_PROCESS_PRIVILEGE
;
79 SeProfileSingleProcessPrivilege
.HighPart
= 0;
80 SeIncreaseBasePriorityPrivilege
.LowPart
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
81 SeIncreaseBasePriorityPrivilege
.HighPart
= 0;
82 SeCreatePagefilePrivilege
.LowPart
= SE_CREATE_PAGEFILE_PRIVILEGE
;
83 SeCreatePagefilePrivilege
.HighPart
= 0;
84 SeCreatePermanentPrivilege
.LowPart
= SE_CREATE_PERMANENT_PRIVILEGE
;
85 SeCreatePermanentPrivilege
.HighPart
= 0;
86 SeBackupPrivilege
.LowPart
= SE_BACKUP_PRIVILEGE
;
87 SeBackupPrivilege
.HighPart
= 0;
88 SeRestorePrivilege
.LowPart
= SE_RESTORE_PRIVILEGE
;
89 SeRestorePrivilege
.HighPart
= 0;
90 SeShutdownPrivilege
.LowPart
= SE_SHUTDOWN_PRIVILEGE
;
91 SeShutdownPrivilege
.HighPart
= 0;
92 SeDebugPrivilege
.LowPart
= SE_DEBUG_PRIVILEGE
;
93 SeDebugPrivilege
.HighPart
= 0;
94 SeAuditPrivilege
.LowPart
= SE_AUDIT_PRIVILEGE
;
95 SeAuditPrivilege
.HighPart
= 0;
96 SeSystemEnvironmentPrivilege
.LowPart
= SE_SYSTEM_ENVIRONMENT_PRIVILEGE
;
97 SeSystemEnvironmentPrivilege
.HighPart
= 0;
98 SeChangeNotifyPrivilege
.LowPart
= SE_CHANGE_NOTIFY_PRIVILEGE
;
99 SeChangeNotifyPrivilege
.HighPart
= 0;
100 SeRemoteShutdownPrivilege
.LowPart
= SE_REMOTE_SHUTDOWN_PRIVILEGE
;
101 SeRemoteShutdownPrivilege
.HighPart
= 0;
102 SeUndockPrivilege
.LowPart
= SE_UNDOCK_PRIVILEGE
;
103 SeUndockPrivilege
.HighPart
= 0;
104 SeSyncAgentPrivilege
.LowPart
= SE_SYNC_AGENT_PRIVILEGE
;
105 SeSyncAgentPrivilege
.HighPart
= 0;
106 SeEnableDelegationPrivilege
.LowPart
= SE_ENABLE_DELEGATION_PRIVILEGE
;
107 SeEnableDelegationPrivilege
.HighPart
= 0;
113 SepPrivilegeCheck(PTOKEN Token
,
114 PLUID_AND_ATTRIBUTES Privileges
,
115 ULONG PrivilegeCount
,
116 ULONG PrivilegeControl
,
117 KPROCESSOR_MODE PreviousMode
)
123 DPRINT("SepPrivilegeCheck() called\n");
127 if (PreviousMode
== KernelMode
)
130 /* Get the number of privileges that are required to match */
131 Required
= (PrivilegeControl
& PRIVILEGE_SET_ALL_NECESSARY
) ? PrivilegeCount
: 1;
133 /* Loop all requested privileges until we found the required ones */
134 for (i
= 0; i
< PrivilegeCount
&& Required
> 0; i
++)
136 /* Loop the privileges of the token */
137 for (j
= 0; j
< Token
->PrivilegeCount
; j
++)
139 /* Check if the LUIDs match */
140 if (Token
->Privileges
[j
].Luid
.LowPart
== Privileges
[i
].Luid
.LowPart
&&
141 Token
->Privileges
[j
].Luid
.HighPart
== Privileges
[i
].Luid
.HighPart
)
143 DPRINT("Found privilege. Attributes: %lx\n",
144 Token
->Privileges
[j
].Attributes
);
146 /* Check if the privilege is enabled */
147 if (Token
->Privileges
[j
].Attributes
& SE_PRIVILEGE_ENABLED
)
149 Privileges
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
153 /* Leave the inner loop */
159 /* Return whether we found all required privileges */
160 return (Required
== 0);
165 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src
,
166 ULONG PrivilegeCount
,
167 KPROCESSOR_MODE PreviousMode
,
168 PLUID_AND_ATTRIBUTES AllocatedMem
,
169 ULONG AllocatedLength
,
171 BOOLEAN CaptureIfKernel
,
172 PLUID_AND_ATTRIBUTES
*Dest
,
176 NTSTATUS Status
= STATUS_SUCCESS
;
180 if (PrivilegeCount
== 0)
184 return STATUS_SUCCESS
;
187 if (PreviousMode
== KernelMode
&& !CaptureIfKernel
)
190 return STATUS_SUCCESS
;
193 /* FIXME - check PrivilegeCount for a valid number so we don't
194 cause an integer overflow or exhaust system resources! */
196 BufferSize
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
197 *Length
= ROUND_UP(BufferSize
, 4); /* round up to a 4 byte alignment */
199 /* probe the buffer */
200 if (PreviousMode
!= KernelMode
)
208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
210 /* Return the exception code */
211 _SEH2_YIELD(return _SEH2_GetExceptionCode());
216 /* allocate enough memory or check if the provided buffer is
217 large enough to hold the array */
218 if (AllocatedMem
!= NULL
)
220 if (AllocatedLength
< BufferSize
)
222 return STATUS_BUFFER_TOO_SMALL
;
225 *Dest
= AllocatedMem
;
229 *Dest
= ExAllocatePool(PoolType
,
233 return STATUS_INSUFFICIENT_RESOURCES
;
237 /* copy the array to the buffer */
244 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
246 Status
= _SEH2_GetExceptionCode();
250 if (!NT_SUCCESS(Status
) && AllocatedMem
== NULL
)
260 SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege
,
261 KPROCESSOR_MODE PreviousMode
,
262 BOOLEAN CaptureIfKernel
)
266 if (Privilege
!= NULL
&&
267 (PreviousMode
!= KernelMode
|| CaptureIfKernel
))
269 ExFreePool(Privilege
);
273 /* PUBLIC FUNCTIONS ***********************************************************/
280 SeAppendPrivileges(IN OUT PACCESS_STATE AccessState
,
281 IN PPRIVILEGE_SET Privileges
)
283 PAUX_ACCESS_DATA AuxData
;
284 ULONG OldPrivilegeSetSize
;
285 ULONG NewPrivilegeSetSize
;
286 PPRIVILEGE_SET PrivilegeSet
;
290 /* Get the Auxiliary Data */
291 AuxData
= AccessState
->AuxData
;
293 /* Calculate the size of the old privilege set */
294 OldPrivilegeSetSize
= sizeof(PRIVILEGE_SET
) +
295 (AuxData
->PrivilegeSet
->PrivilegeCount
- 1) * sizeof(LUID_AND_ATTRIBUTES
);
297 if (AuxData
->PrivilegeSet
->PrivilegeCount
+
298 Privileges
->PrivilegeCount
> INITIAL_PRIVILEGE_COUNT
)
300 /* Calculate the size of the new privilege set */
301 NewPrivilegeSetSize
= OldPrivilegeSetSize
+
302 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
304 /* Allocate a new privilege set */
305 PrivilegeSet
= ExAllocatePool(PagedPool
, NewPrivilegeSetSize
);
306 if (PrivilegeSet
== NULL
)
307 return STATUS_INSUFFICIENT_RESOURCES
;
309 /* Copy original privileges from the acess state */
310 RtlCopyMemory(PrivilegeSet
,
311 AuxData
->PrivilegeSet
,
312 OldPrivilegeSetSize
);
314 /* Append privileges from the privilege set*/
315 RtlCopyMemory((PVOID
)((ULONG_PTR
)PrivilegeSet
+ OldPrivilegeSetSize
),
316 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
317 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
319 /* Adjust the number of privileges in the new privilege set */
320 PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
322 /* Free the old privilege set if it was allocated */
323 if (AccessState
->PrivilegesAllocated
== TRUE
)
324 ExFreePool(AuxData
->PrivilegeSet
);
326 /* Now we are using an allocated privilege set */
327 AccessState
->PrivilegesAllocated
= TRUE
;
329 /* Assign the new privileges to the access state */
330 AuxData
->PrivilegeSet
= PrivilegeSet
;
334 /* Append privileges */
335 RtlCopyMemory((PVOID
)((ULONG_PTR
)AuxData
->PrivilegeSet
+ OldPrivilegeSetSize
),
336 (PVOID
)((ULONG_PTR
)Privileges
+ sizeof(PRIVILEGE_SET
) - sizeof(LUID_AND_ATTRIBUTES
)),
337 Privileges
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
339 /* Adjust the number of privileges in the target privilege set */
340 AuxData
->PrivilegeSet
->PrivilegeCount
+= Privileges
->PrivilegeCount
;
343 return STATUS_SUCCESS
;
351 SeFreePrivileges(IN PPRIVILEGE_SET Privileges
)
354 ExFreePool(Privileges
);
362 SePrivilegeCheck(PPRIVILEGE_SET Privileges
,
363 PSECURITY_SUBJECT_CONTEXT SubjectContext
,
364 KPROCESSOR_MODE PreviousMode
)
366 PACCESS_TOKEN Token
= NULL
;
370 if (SubjectContext
->ClientToken
== NULL
)
372 Token
= SubjectContext
->PrimaryToken
;
376 Token
= SubjectContext
->ClientToken
;
377 if (SubjectContext
->ImpersonationLevel
< 2)
383 return SepPrivilegeCheck(Token
,
384 Privileges
->Privilege
,
385 Privileges
->PrivilegeCount
,
395 SeSinglePrivilegeCheck(IN LUID PrivilegeValue
,
396 IN KPROCESSOR_MODE PreviousMode
)
398 SECURITY_SUBJECT_CONTEXT SubjectContext
;
404 SeCaptureSubjectContext(&SubjectContext
);
406 Priv
.PrivilegeCount
= 1;
407 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
408 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
409 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
411 Result
= SePrivilegeCheck(&Priv
,
415 if (PreviousMode
!= KernelMode
)
418 SePrivilegedServiceAuditAlarm(0,
424 SeReleaseSubjectContext(&SubjectContext
);
431 SeCheckPrivilegedObject(IN LUID PrivilegeValue
,
432 IN HANDLE ObjectHandle
,
433 IN ACCESS_MASK DesiredAccess
,
434 IN KPROCESSOR_MODE PreviousMode
)
436 SECURITY_SUBJECT_CONTEXT SubjectContext
;
442 SeCaptureSubjectContext(&SubjectContext
);
444 Priv
.PrivilegeCount
= 1;
445 Priv
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
446 Priv
.Privilege
[0].Luid
= PrivilegeValue
;
447 Priv
.Privilege
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
449 Result
= SePrivilegeCheck(&Priv
, &SubjectContext
, PreviousMode
);
450 if (PreviousMode
!= KernelMode
)
453 SePrivilegeObjectAuditAlarm(ObjectHandle
,
462 SeReleaseSubjectContext(&SubjectContext
);
467 /* SYSTEM CALLS ***************************************************************/
471 NtPrivilegeCheck(IN HANDLE ClientToken
,
472 IN PPRIVILEGE_SET RequiredPrivileges
,
475 PLUID_AND_ATTRIBUTES Privileges
;
477 ULONG PrivilegeCount
= 0;
478 ULONG PrivilegeControl
= 0;
481 KPROCESSOR_MODE PreviousMode
;
486 PreviousMode
= KeGetPreviousMode();
488 /* probe the buffers */
489 if (PreviousMode
!= KernelMode
)
493 ProbeForWrite(RequiredPrivileges
,
494 FIELD_OFFSET(PRIVILEGE_SET
,
498 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
499 PrivilegeControl
= RequiredPrivileges
->Control
;
501 /* Check PrivilegeCount to avoid an integer overflow! */
502 if (FIELD_OFFSET(PRIVILEGE_SET
,
503 Privilege
[PrivilegeCount
]) /
504 sizeof(RequiredPrivileges
->Privilege
[0]) != PrivilegeCount
)
506 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
509 /* probe all of the array */
510 ProbeForWrite(RequiredPrivileges
,
511 FIELD_OFFSET(PRIVILEGE_SET
,
512 Privilege
[PrivilegeCount
]),
515 ProbeForWriteBoolean(Result
);
517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
519 /* Return the exception code */
520 _SEH2_YIELD(return _SEH2_GetExceptionCode());
526 PrivilegeCount
= RequiredPrivileges
->PrivilegeCount
;
527 PrivilegeControl
= RequiredPrivileges
->Control
;
530 /* reference the token and make sure we're
531 not doing an anonymous impersonation */
532 Status
= ObReferenceObjectByHandle(ClientToken
,
538 if (!NT_SUCCESS(Status
))
543 if (Token
->TokenType
== TokenImpersonation
&&
544 Token
->ImpersonationLevel
< SecurityIdentification
)
546 ObDereferenceObject(Token
);
547 return STATUS_BAD_IMPERSONATION_LEVEL
;
550 /* capture the privileges */
551 Status
= SeCaptureLuidAndAttributesArray(RequiredPrivileges
->Privilege
,
560 if (!NT_SUCCESS(Status
))
562 ObDereferenceObject (Token
);
566 CheckResult
= SepPrivilegeCheck(Token
,
572 ObDereferenceObject(Token
);
574 /* return the array */
577 RtlCopyMemory(RequiredPrivileges
->Privilege
,
579 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
580 *Result
= CheckResult
;
581 Status
= STATUS_SUCCESS
;
583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
585 Status
= _SEH2_GetExceptionCode();
589 SeReleaseLuidAndAttributesArray(Privileges
,