2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/access.c
5 * PURPOSE: Access state functions
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) -
8 * Based on patch by Javier M. Mellid
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 ERESOURCE SepSubjectContextLock
;
21 /* PRIVATE FUNCTIONS **********************************************************/
25 SepSidInTokenEx(IN PACCESS_TOKEN _Token
,
26 IN PSID PrincipalSelfSid
,
29 IN BOOLEAN Restricted
)
32 PTOKEN Token
= (PTOKEN
)_Token
;
33 PISID TokenSid
, Sid
= (PISID
)_Sid
;
34 PSID_AND_ATTRIBUTES SidAndAttributes
;
35 ULONG SidCount
, SidLength
;
39 /* Not yet supported */
40 ASSERT(PrincipalSelfSid
== NULL
);
41 ASSERT(Restricted
== FALSE
);
43 /* Check if a principal SID was given, and this is our current SID already */
44 if ((PrincipalSelfSid
) && (RtlEqualSid(SePrincipalSelfSid
, Sid
)))
46 /* Just use the principal SID in this case */
47 Sid
= PrincipalSelfSid
;
50 /* Check if this is a restricted token or not */
53 /* Use the restricted SIDs and count */
54 SidAndAttributes
= Token
->RestrictedSids
;
55 SidCount
= Token
->RestrictedSidCount
;
59 /* Use the normal SIDs and count */
60 SidAndAttributes
= Token
->UserAndGroups
;
61 SidCount
= Token
->UserAndGroupCount
;
64 /* Do checks here by hand instead of the usual 4 function calls */
65 SidLength
= FIELD_OFFSET(SID
,
66 SubAuthority
[Sid
->SubAuthorityCount
]);
67 SidMetadata
= *(PUSHORT
)&Sid
->Revision
;
70 for (i
= 0; i
< SidCount
; i
++)
72 TokenSid
= (PISID
)SidAndAttributes
->Sid
;
74 UNICODE_STRING sidString
;
75 RtlConvertSidToUnicodeString(&sidString
, TokenSid
, TRUE
);
76 DPRINT1("SID in Token: %wZ\n", &sidString
);
77 RtlFreeUnicodeString(&sidString
);
79 /* Check if the SID metadata matches */
80 if (*(PUSHORT
)&TokenSid
->Revision
== SidMetadata
)
82 /* Check if the SID data matches */
83 if (RtlEqualMemory(Sid
, TokenSid
, SidLength
))
85 /* Check if the group is enabled, or used for deny only */
86 if ((!(i
) && !(SidAndAttributes
->Attributes
& SE_GROUP_USE_FOR_DENY_ONLY
)) ||
87 (SidAndAttributes
->Attributes
& SE_GROUP_ENABLED
) ||
88 ((Deny
) && (SidAndAttributes
->Attributes
& SE_GROUP_USE_FOR_DENY_ONLY
)))
95 /* SID is not present */
101 /* Move to the next SID */
105 /* SID is not present */
111 SepSidInToken(IN PACCESS_TOKEN _Token
,
114 /* Call extended API */
115 return SepSidInTokenEx(_Token
, NULL
, Sid
, FALSE
, FALSE
);
120 SepTokenIsOwner(IN PACCESS_TOKEN _Token
,
121 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
122 IN BOOLEAN TokenLocked
)
126 PTOKEN Token
= _Token
;
128 /* Get the owner SID */
129 Sid
= SepGetOwnerFromDescriptor(SecurityDescriptor
);
132 /* Lock the token if needed */
133 if (!TokenLocked
) SepAcquireTokenLockShared(Token
);
135 /* Check if the owner SID is found, handling restricted case as well */
136 Result
= SepSidInToken(Token
, Sid
);
137 if ((Result
) && (Token
->TokenFlags
& TOKEN_IS_RESTRICTED
))
139 Result
= SepSidInTokenEx(Token
, NULL
, Sid
, FALSE
, TRUE
);
142 /* Release the lock if we had acquired it */
143 if (!TokenLocked
) SepReleaseTokenLock(Token
);
145 /* Return the result */
151 SeGetTokenControlInformation(IN PACCESS_TOKEN _Token
,
152 OUT PTOKEN_CONTROL TokenControl
)
154 PTOKEN Token
= _Token
;
157 /* Capture the main fields */
158 TokenControl
->AuthenticationId
= Token
->AuthenticationId
;
159 TokenControl
->TokenId
= Token
->TokenId
;
160 TokenControl
->TokenSource
= Token
->TokenSource
;
163 SepAcquireTokenLockShared(Token
);
165 /* Capture the modified ID */
166 TokenControl
->ModifiedId
= Token
->ModifiedId
;
169 SepReleaseTokenLock(Token
);
174 SepCreateClientSecurity(IN PACCESS_TOKEN Token
,
175 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos
,
176 IN BOOLEAN ServerIsRemote
,
177 IN TOKEN_TYPE TokenType
,
178 IN BOOLEAN ThreadEffectiveOnly
,
179 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
,
180 OUT PSECURITY_CLIENT_CONTEXT ClientContext
)
183 PACCESS_TOKEN NewToken
;
186 /* Check for bogus impersonation level */
187 if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos
->ImpersonationLevel
))
190 return STATUS_INVALID_PARAMETER
;
193 /* Check what kind of token this is */
194 if (TokenType
!= TokenImpersonation
)
196 /* On a primary token, if we do direct access, copy the flag from the QOS */
197 ClientContext
->DirectAccessEffectiveOnly
= ClientSecurityQos
->EffectiveOnly
;
201 /* This is an impersonation token, is the level ok? */
202 if (ClientSecurityQos
->ImpersonationLevel
> ImpersonationLevel
)
205 return STATUS_BAD_IMPERSONATION_LEVEL
;
208 /* Is the level too low, or are we doing something other than delegation remotely */
209 if ((ImpersonationLevel
== SecurityAnonymous
) ||
210 (ImpersonationLevel
== SecurityIdentification
) ||
211 ((ServerIsRemote
) && (ImpersonationLevel
!= SecurityDelegation
)))
214 return STATUS_BAD_IMPERSONATION_LEVEL
;
217 /* Pick either the thread setting or the QOS setting */
218 ClientContext
->DirectAccessEffectiveOnly
=
219 ((ThreadEffectiveOnly
) || (ClientSecurityQos
->EffectiveOnly
)) ? TRUE
: FALSE
;
222 /* Is this static tracking */
223 if (ClientSecurityQos
->ContextTrackingMode
== SECURITY_STATIC_TRACKING
)
225 /* Do not use direct access and make a copy */
226 ClientContext
->DirectlyAccessClientToken
= FALSE
;
227 Status
= SeCopyClientToken(Token
,
228 ClientSecurityQos
->ImpersonationLevel
,
231 if (!NT_SUCCESS(Status
))
236 /* Use direct access and check if this is local */
237 ClientContext
->DirectlyAccessClientToken
= TRUE
;
240 /* We are doing delegation, so make a copy of the control data */
241 SeGetTokenControlInformation(Token
,
242 &ClientContext
->ClientTokenControl
);
245 /* Keep the same token */
249 /* Fill out the context and return success */
250 ClientContext
->SecurityQos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
251 ClientContext
->SecurityQos
.ImpersonationLevel
= ClientSecurityQos
->ImpersonationLevel
;
252 ClientContext
->SecurityQos
.ContextTrackingMode
= ClientSecurityQos
->ContextTrackingMode
;
253 ClientContext
->SecurityQos
.EffectiveOnly
= ClientSecurityQos
->EffectiveOnly
;
254 ClientContext
->ServerIsRemote
= ServerIsRemote
;
255 ClientContext
->ClientToken
= NewToken
;
256 return STATUS_SUCCESS
;
259 /* PUBLIC FUNCTIONS ***********************************************************/
266 SeCaptureSubjectContextEx(IN PETHREAD Thread
,
267 IN PEPROCESS Process
,
268 OUT PSECURITY_SUBJECT_CONTEXT SubjectContext
)
270 BOOLEAN CopyOnOpen
, EffectiveOnly
;
274 /* Save the unique ID */
275 SubjectContext
->ProcessAuditId
= Process
->UniqueProcessId
;
277 /* Check if we have a thread */
280 /* We don't, so no token */
281 SubjectContext
->ClientToken
= NULL
;
285 /* Get the impersonation token */
286 SubjectContext
->ClientToken
= PsReferenceImpersonationToken(Thread
,
289 &SubjectContext
->ImpersonationLevel
);
292 /* Get the primary token */
293 SubjectContext
->PrimaryToken
= PsReferencePrimaryToken(Process
);
301 SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext
)
303 /* Call the extended API */
304 SeCaptureSubjectContextEx(PsGetCurrentThread(),
305 PsGetCurrentProcess(),
314 SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
316 PTOKEN PrimaryToken
, ClientToken
;
319 /* Read both tokens */
320 PrimaryToken
= SubjectContext
->PrimaryToken
;
321 ClientToken
= SubjectContext
->ClientToken
;
323 /* Always lock the primary */
324 SepAcquireTokenLockShared(PrimaryToken
);
326 /* Lock the impersonation one if it's there */
327 if (!ClientToken
) return;
328 SepAcquireTokenLockShared(ClientToken
);
336 SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
338 PTOKEN PrimaryToken
, ClientToken
;
341 /* Read both tokens */
342 PrimaryToken
= SubjectContext
->PrimaryToken
;
343 ClientToken
= SubjectContext
->ClientToken
;
345 /* Unlock the impersonation one if it's there */
348 SepReleaseTokenLock(ClientToken
);
351 /* Always unlock the primary one */
352 SepReleaseTokenLock(PrimaryToken
);
360 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
364 /* Drop reference on the primary */
365 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, SubjectContext
->PrimaryToken
);
366 SubjectContext
->PrimaryToken
= NULL
;
368 /* Drop reference on the impersonation, if there was one */
369 PsDereferenceImpersonationToken(SubjectContext
->ClientToken
);
370 SubjectContext
->ClientToken
= NULL
;
378 SeCreateAccessStateEx(IN PETHREAD Thread
,
379 IN PEPROCESS Process
,
380 IN OUT PACCESS_STATE AccessState
,
381 IN PAUX_ACCESS_DATA AuxData
,
382 IN ACCESS_MASK Access
,
383 IN PGENERIC_MAPPING GenericMapping
)
385 ACCESS_MASK AccessMask
= Access
;
389 /* Map the Generic Acess to Specific Access if we have a Mapping */
390 if ((Access
& GENERIC_ACCESS
) && (GenericMapping
))
392 RtlMapGenericMask(&AccessMask
, GenericMapping
);
395 /* Initialize the Access State */
396 RtlZeroMemory(AccessState
, sizeof(ACCESS_STATE
));
397 ASSERT(AccessState
->SecurityDescriptor
== NULL
);
398 ASSERT(AccessState
->PrivilegesAllocated
== FALSE
);
400 /* Initialize and save aux data */
401 RtlZeroMemory(AuxData
, sizeof(AUX_ACCESS_DATA
));
402 AccessState
->AuxData
= AuxData
;
404 /* Capture the Subject Context */
405 SeCaptureSubjectContextEx(Thread
,
407 &AccessState
->SubjectSecurityContext
);
409 /* Set Access State Data */
410 AccessState
->RemainingDesiredAccess
= AccessMask
;
411 AccessState
->OriginalDesiredAccess
= AccessMask
;
412 ExAllocateLocallyUniqueId(&AccessState
->OperationID
);
414 /* Get the Token to use */
415 Token
= SeQuerySubjectContextToken(&AccessState
->SubjectSecurityContext
);
417 /* Check for Travers Privilege */
418 if (Token
->TokenFlags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
)
420 /* Preserve the Traverse Privilege */
421 AccessState
->Flags
= TOKEN_HAS_TRAVERSE_PRIVILEGE
;
424 /* Set the Auxiliary Data */
425 AuxData
->PrivilegeSet
= (PPRIVILEGE_SET
)((ULONG_PTR
)AccessState
+
426 FIELD_OFFSET(ACCESS_STATE
,
428 if (GenericMapping
) AuxData
->GenericMapping
= *GenericMapping
;
431 return STATUS_SUCCESS
;
439 SeCreateAccessState(IN OUT PACCESS_STATE AccessState
,
440 IN PAUX_ACCESS_DATA AuxData
,
441 IN ACCESS_MASK Access
,
442 IN PGENERIC_MAPPING GenericMapping
)
446 /* Call the extended API */
447 return SeCreateAccessStateEx(PsGetCurrentThread(),
448 PsGetCurrentProcess(),
460 SeDeleteAccessState(IN PACCESS_STATE AccessState
)
462 PAUX_ACCESS_DATA AuxData
;
465 /* Get the Auxiliary Data */
466 AuxData
= AccessState
->AuxData
;
468 /* Deallocate Privileges */
469 if (AccessState
->PrivilegesAllocated
)
470 ExFreePoolWithTag(AuxData
->PrivilegeSet
, TAG_PRIVILEGE_SET
);
472 /* Deallocate Name and Type Name */
473 if (AccessState
->ObjectName
.Buffer
)
475 ExFreePool(AccessState
->ObjectName
.Buffer
);
478 if (AccessState
->ObjectTypeName
.Buffer
)
480 ExFreePool(AccessState
->ObjectTypeName
.Buffer
);
483 /* Release the Subject Context */
484 SeReleaseSubjectContext(&AccessState
->SubjectSecurityContext
);
492 SeSetAccessStateGenericMapping(IN PACCESS_STATE AccessState
,
493 IN PGENERIC_MAPPING GenericMapping
)
497 /* Set the Generic Mapping */
498 ((PAUX_ACCESS_DATA
)AccessState
->AuxData
)->GenericMapping
= *GenericMapping
;
506 SeCreateClientSecurity(IN PETHREAD Thread
,
507 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
508 IN BOOLEAN RemoteClient
,
509 OUT PSECURITY_CLIENT_CONTEXT ClientContext
)
511 TOKEN_TYPE TokenType
;
512 BOOLEAN ThreadEffectiveOnly
;
513 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
518 /* Reference the correct token */
519 Token
= PsReferenceEffectiveToken(Thread
,
521 &ThreadEffectiveOnly
,
522 &ImpersonationLevel
);
524 /* Create client security from it */
525 Status
= SepCreateClientSecurity(Token
,
533 /* Check if we failed or static tracking was used */
534 if (!(NT_SUCCESS(Status
)) || (Qos
->ContextTrackingMode
== SECURITY_STATIC_TRACKING
))
536 /* Dereference our copy since it's not being used */
537 ObDereferenceObject(Token
);
549 SeCreateClientSecurityFromSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
,
550 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos
,
551 IN BOOLEAN ServerIsRemote
,
552 OUT PSECURITY_CLIENT_CONTEXT ClientContext
)
558 /* Get the right token and reference it */
559 Token
= SeQuerySubjectContextToken(SubjectContext
);
560 ObReferenceObject(Token
);
562 /* Create the context */
563 Status
= SepCreateClientSecurity(Token
,
566 SubjectContext
->ClientToken
?
567 TokenImpersonation
: TokenPrimary
,
569 SubjectContext
->ImpersonationLevel
,
572 /* Check if we failed or static tracking was used */
573 if (!(NT_SUCCESS(Status
)) ||
574 (ClientSecurityQos
->ContextTrackingMode
== SECURITY_STATIC_TRACKING
))
576 /* Dereference our copy since it's not being used */
577 ObDereferenceObject(Token
);
589 SeImpersonateClientEx(IN PSECURITY_CLIENT_CONTEXT ClientContext
,
590 IN PETHREAD ServerThread OPTIONAL
)
592 BOOLEAN EffectiveOnly
;
595 /* Check if direct access is requested */
596 if (!ClientContext
->DirectlyAccessClientToken
)
598 /* No, so get the flag from QOS */
599 EffectiveOnly
= ClientContext
->SecurityQos
.EffectiveOnly
;
603 /* Yes, so see if direct access should be effective only */
604 EffectiveOnly
= ClientContext
->DirectAccessEffectiveOnly
;
607 /* Use the current thread if one was not passed */
608 if (!ServerThread
) ServerThread
= PsGetCurrentThread();
610 /* Call the lower layer routine */
611 return PsImpersonateClient(ServerThread
,
612 ClientContext
->ClientToken
,
615 ClientContext
->SecurityQos
.ImpersonationLevel
);
623 SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext
,
624 IN PETHREAD ServerThread OPTIONAL
)
628 /* Call the new API */
629 SeImpersonateClientEx(ClientContext
, ServerThread
);