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 it */
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
= ((ThreadEffectiveOnly
) ||
219 (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
, ImpersonationLevel
, 0, &NewToken
);
228 if (!NT_SUCCESS(Status
)) return Status
;
232 /* Use direct access and check if this is local */
233 ClientContext
->DirectlyAccessClientToken
= TRUE
;
236 /* We are doing delegation, so make a copy of the control data */
237 SeGetTokenControlInformation(Token
,
238 &ClientContext
->ClientTokenControl
);
241 /* Keep the same token */
245 /* Fill out the context and return success */
246 ClientContext
->SecurityQos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
247 ClientContext
->SecurityQos
.ImpersonationLevel
= ClientSecurityQos
->ImpersonationLevel
;
248 ClientContext
->SecurityQos
.ContextTrackingMode
= ClientSecurityQos
->ContextTrackingMode
;
249 ClientContext
->SecurityQos
.EffectiveOnly
= ClientSecurityQos
->EffectiveOnly
;
250 ClientContext
->ServerIsRemote
= ServerIsRemote
;
251 ClientContext
->ClientToken
= NewToken
;
252 return STATUS_SUCCESS
;
255 /* PUBLIC FUNCTIONS ***********************************************************/
262 SeCaptureSubjectContextEx(IN PETHREAD Thread
,
263 IN PEPROCESS Process
,
264 OUT PSECURITY_SUBJECT_CONTEXT SubjectContext
)
266 BOOLEAN CopyOnOpen
, EffectiveOnly
;
270 /* Save the unique ID */
271 SubjectContext
->ProcessAuditId
= Process
->UniqueProcessId
;
273 /* Check if we have a thread */
276 /* We don't, so no token */
277 SubjectContext
->ClientToken
= NULL
;
281 /* Get the impersonation token */
282 SubjectContext
->ClientToken
= PsReferenceImpersonationToken(Thread
,
285 &SubjectContext
->ImpersonationLevel
);
288 /* Get the primary token */
289 SubjectContext
->PrimaryToken
= PsReferencePrimaryToken(Process
);
297 SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext
)
299 /* Call the extended API */
300 SeCaptureSubjectContextEx(PsGetCurrentThread(),
301 PsGetCurrentProcess(),
310 SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
312 PTOKEN PrimaryToken
, ClientToken
;
315 /* Read both tokens */
316 PrimaryToken
= SubjectContext
->PrimaryToken
;
317 ClientToken
= SubjectContext
->ClientToken
;
319 /* Always lock the primary */
320 SepAcquireTokenLockShared(PrimaryToken
);
322 /* Lock the impersonation one if it's there */
323 if (!ClientToken
) return;
324 SepAcquireTokenLockShared(ClientToken
);
332 SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
334 PTOKEN PrimaryToken
, ClientToken
;
337 /* Read both tokens */
338 PrimaryToken
= SubjectContext
->PrimaryToken
;
339 ClientToken
= SubjectContext
->ClientToken
;
341 /* Always unlock the primary one */
342 SepReleaseTokenLock(PrimaryToken
);
344 /* Unlock the impersonation one if it's there */
345 if (!ClientToken
) return;
346 SepReleaseTokenLock(ClientToken
);
354 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
)
358 /* Drop reference on the primary */
359 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, SubjectContext
->PrimaryToken
);
360 SubjectContext
->PrimaryToken
= NULL
;
362 /* Drop reference on the impersonation, if there was one */
363 PsDereferenceImpersonationToken(SubjectContext
->ClientToken
);
364 SubjectContext
->ClientToken
= NULL
;
372 SeCreateAccessStateEx(IN PETHREAD Thread
,
373 IN PEPROCESS Process
,
374 IN OUT PACCESS_STATE AccessState
,
375 IN PAUX_ACCESS_DATA AuxData
,
376 IN ACCESS_MASK Access
,
377 IN PGENERIC_MAPPING GenericMapping
)
379 ACCESS_MASK AccessMask
= Access
;
383 /* Map the Generic Acess to Specific Access if we have a Mapping */
384 if ((Access
& GENERIC_ACCESS
) && (GenericMapping
))
386 RtlMapGenericMask(&AccessMask
, GenericMapping
);
389 /* Initialize the Access State */
390 RtlZeroMemory(AccessState
, sizeof(ACCESS_STATE
));
391 ASSERT(AccessState
->SecurityDescriptor
== NULL
);
392 ASSERT(AccessState
->PrivilegesAllocated
== FALSE
);
394 /* Initialize and save aux data */
395 RtlZeroMemory(AuxData
, sizeof(AUX_ACCESS_DATA
));
396 AccessState
->AuxData
= AuxData
;
398 /* Capture the Subject Context */
399 SeCaptureSubjectContextEx(Thread
,
401 &AccessState
->SubjectSecurityContext
);
403 /* Set Access State Data */
404 AccessState
->RemainingDesiredAccess
= AccessMask
;
405 AccessState
->OriginalDesiredAccess
= AccessMask
;
406 ExpAllocateLocallyUniqueId(&AccessState
->OperationID
);
408 /* Get the Token to use */
409 Token
= SeQuerySubjectContextToken(&AccessState
->SubjectSecurityContext
);
411 /* Check for Travers Privilege */
412 if (Token
->TokenFlags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
)
414 /* Preserve the Traverse Privilege */
415 AccessState
->Flags
= TOKEN_HAS_TRAVERSE_PRIVILEGE
;
418 /* Set the Auxiliary Data */
419 AuxData
->PrivilegeSet
= (PPRIVILEGE_SET
)((ULONG_PTR
)AccessState
+
420 FIELD_OFFSET(ACCESS_STATE
,
422 if (GenericMapping
) AuxData
->GenericMapping
= *GenericMapping
;
425 return STATUS_SUCCESS
;
433 SeCreateAccessState(IN OUT PACCESS_STATE AccessState
,
434 IN PAUX_ACCESS_DATA AuxData
,
435 IN ACCESS_MASK Access
,
436 IN PGENERIC_MAPPING GenericMapping
)
440 /* Call the extended API */
441 return SeCreateAccessStateEx(PsGetCurrentThread(),
442 PsGetCurrentProcess(),
454 SeDeleteAccessState(IN PACCESS_STATE AccessState
)
456 PAUX_ACCESS_DATA AuxData
;
459 /* Get the Auxiliary Data */
460 AuxData
= AccessState
->AuxData
;
462 /* Deallocate Privileges */
463 if (AccessState
->PrivilegesAllocated
) ExFreePool(AuxData
->PrivilegeSet
);
465 /* Deallocate Name and Type Name */
466 if (AccessState
->ObjectName
.Buffer
)
468 ExFreePool(AccessState
->ObjectName
.Buffer
);
471 if (AccessState
->ObjectTypeName
.Buffer
)
473 ExFreePool(AccessState
->ObjectTypeName
.Buffer
);
476 /* Release the Subject Context */
477 SeReleaseSubjectContext(&AccessState
->SubjectSecurityContext
);
485 SeSetAccessStateGenericMapping(IN PACCESS_STATE AccessState
,
486 IN PGENERIC_MAPPING GenericMapping
)
490 /* Set the Generic Mapping */
491 ((PAUX_ACCESS_DATA
)AccessState
->AuxData
)->GenericMapping
= *GenericMapping
;
499 SeCreateClientSecurity(IN PETHREAD Thread
,
500 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
501 IN BOOLEAN RemoteClient
,
502 OUT PSECURITY_CLIENT_CONTEXT ClientContext
)
504 TOKEN_TYPE TokenType
;
505 BOOLEAN ThreadEffectiveOnly
;
506 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
511 /* Reference the correct token */
512 Token
= PsReferenceEffectiveToken(Thread
,
514 &ThreadEffectiveOnly
,
515 &ImpersonationLevel
);
517 /* Create client security from it */
518 Status
= SepCreateClientSecurity(Token
,
526 /* Check if we failed or static tracking was used */
527 if (!(NT_SUCCESS(Status
)) || (Qos
->ContextTrackingMode
== SECURITY_STATIC_TRACKING
))
529 /* Dereference our copy since it's not being used */
530 ObDereferenceObject(Token
);
542 SeCreateClientSecurityFromSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext
,
543 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos
,
544 IN BOOLEAN ServerIsRemote
,
545 OUT PSECURITY_CLIENT_CONTEXT ClientContext
)
551 /* Get the right token and reference it */
552 Token
= SeQuerySubjectContextToken(SubjectContext
);
553 ObReferenceObject(Token
);
555 /* Create the context */
556 Status
= SepCreateClientSecurity(Token
,
559 SubjectContext
->ClientToken
?
560 TokenImpersonation
: TokenPrimary
,
562 SubjectContext
->ImpersonationLevel
,
565 /* Check if we failed or static tracking was used */
566 if (!(NT_SUCCESS(Status
)) ||
567 (ClientSecurityQos
->ContextTrackingMode
== SECURITY_STATIC_TRACKING
))
569 /* Dereference our copy since it's not being used */
570 ObDereferenceObject(Token
);
582 SeImpersonateClientEx(IN PSECURITY_CLIENT_CONTEXT ClientContext
,
583 IN PETHREAD ServerThread OPTIONAL
)
585 BOOLEAN EffectiveOnly
;
588 /* Check if direct access is requested */
589 if (!ClientContext
->DirectlyAccessClientToken
)
591 /* No, so get the flag from QOS */
592 EffectiveOnly
= ClientContext
->SecurityQos
.EffectiveOnly
;
596 /* Yes, so see if direct access should be effective only */
597 EffectiveOnly
= ClientContext
->DirectAccessEffectiveOnly
;
600 /* Use the current thread if one was not passed */
601 if (!ServerThread
) ServerThread
= PsGetCurrentThread();
603 /* Call the lower layer routine */
604 return PsImpersonateClient(ServerThread
,
605 ClientContext
->ClientToken
,
608 ClientContext
->SecurityQos
.ImpersonationLevel
);
616 SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext
,
617 IN PETHREAD ServerThread OPTIONAL
)
621 /* Call the new API */
622 SeImpersonateClientEx(ClientContext
, ServerThread
);