[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
[reactos.git] / ntoskrnl / se / access.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security access state functions support
5 * COPYRIGHT: Copyright Alex Ionescu <alex@relsoft.net>
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <debug.h>
13
14 /* GLOBALS ********************************************************************/
15
16 ERESOURCE SepSubjectContextLock;
17
18 /* PRIVATE FUNCTIONS **********************************************************/
19
20 /**
21 * @brief
22 * Checks if a SID is present in a token.
23 *
24 * @param[in] _Token
25 * A valid token object.
26 *
27 * @param[in] PrincipalSelfSid
28 * A principal self SID.
29 *
30 * @param[in] _Sid
31 * A regular SID.
32 *
33 * @param[in] Deny
34 * If set to TRUE, the caller expected that a SID in a token
35 * must be a deny-only SID, that is, access checks are performed
36 * only for deny-only ACEs of the said SID.
37 *
38 * @param[in] Restricted
39 * If set to TRUE, the caller expects that a SID in a token is
40 * restricted.
41 *
42 * @return
43 * Returns TRUE if the specified SID in the call is present in the token,
44 * FALSE otherwise.
45 */
46 BOOLEAN
47 NTAPI
48 SepSidInTokenEx(
49 _In_ PACCESS_TOKEN _Token,
50 _In_ PSID PrincipalSelfSid,
51 _In_ PSID _Sid,
52 _In_ BOOLEAN Deny,
53 _In_ BOOLEAN Restricted)
54 {
55 ULONG i;
56 PTOKEN Token = (PTOKEN)_Token;
57 PISID TokenSid, Sid = (PISID)_Sid;
58 PSID_AND_ATTRIBUTES SidAndAttributes;
59 ULONG SidCount, SidLength;
60 USHORT SidMetadata;
61 PAGED_CODE();
62
63 /* Not yet supported */
64 ASSERT(PrincipalSelfSid == NULL);
65 ASSERT(Restricted == FALSE);
66
67 /* Check if a principal SID was given, and this is our current SID already */
68 if ((PrincipalSelfSid) && (RtlEqualSid(SePrincipalSelfSid, Sid)))
69 {
70 /* Just use the principal SID in this case */
71 Sid = PrincipalSelfSid;
72 }
73
74 /* Check if this is a restricted token or not */
75 if (Restricted)
76 {
77 /* Use the restricted SIDs and count */
78 SidAndAttributes = Token->RestrictedSids;
79 SidCount = Token->RestrictedSidCount;
80 }
81 else
82 {
83 /* Use the normal SIDs and count */
84 SidAndAttributes = Token->UserAndGroups;
85 SidCount = Token->UserAndGroupCount;
86 }
87
88 /* Do checks here by hand instead of the usual 4 function calls */
89 SidLength = FIELD_OFFSET(SID,
90 SubAuthority[Sid->SubAuthorityCount]);
91 SidMetadata = *(PUSHORT)&Sid->Revision;
92
93 /* Loop every SID */
94 for (i = 0; i < SidCount; i++)
95 {
96 TokenSid = (PISID)SidAndAttributes->Sid;
97 #if SE_SID_DEBUG
98 UNICODE_STRING sidString;
99 RtlConvertSidToUnicodeString(&sidString, TokenSid, TRUE);
100 DPRINT1("SID in Token: %wZ\n", &sidString);
101 RtlFreeUnicodeString(&sidString);
102 #endif
103 /* Check if the SID metadata matches */
104 if (*(PUSHORT)&TokenSid->Revision == SidMetadata)
105 {
106 /* Check if the SID data matches */
107 if (RtlEqualMemory(Sid, TokenSid, SidLength))
108 {
109 /* Check if the group is enabled, or used for deny only */
110 if ((!(i) && !(SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) ||
111 (SidAndAttributes->Attributes & SE_GROUP_ENABLED) ||
112 ((Deny) && (SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)))
113 {
114 /* SID is present */
115 return TRUE;
116 }
117 else
118 {
119 /* SID is not present */
120 return FALSE;
121 }
122 }
123 }
124
125 /* Move to the next SID */
126 SidAndAttributes++;
127 }
128
129 /* SID is not present */
130 return FALSE;
131 }
132
133 /**
134 * @brief
135 * Checks if a SID is present in a token.
136 *
137 * @param[in] _Token
138 * A valid token object.
139 *
140 * @param[in] _Sid
141 * A regular SID.
142 *
143 * @return
144 * Returns TRUE if the specified SID in the call is present in the token,
145 * FALSE otherwise.
146 */
147 BOOLEAN
148 NTAPI
149 SepSidInToken(
150 _In_ PACCESS_TOKEN _Token,
151 _In_ PSID Sid)
152 {
153 /* Call extended API */
154 return SepSidInTokenEx(_Token, NULL, Sid, FALSE, FALSE);
155 }
156
157 /**
158 * @brief
159 * Checks if a token belongs to the main user, being the owner.
160 *
161 * @param[in] _Token
162 * A valid token object.
163 *
164 * @param[in] SecurityDescriptor
165 * A security descriptor where the owner is to be found.
166 *
167 * @param[in] TokenLocked
168 * If set to TRUE, the token has been already locked and there's
169 * no need to lock it again. Otherwise the function will acquire
170 * the lock.
171 *
172 * @return
173 * Returns TRUE if the token belongs to a owner, FALSE otherwise.
174 */
175 BOOLEAN
176 NTAPI
177 SepTokenIsOwner(
178 _In_ PACCESS_TOKEN _Token,
179 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
180 _In_ BOOLEAN TokenLocked)
181 {
182 PSID Sid;
183 BOOLEAN Result;
184 PTOKEN Token = _Token;
185
186 /* Get the owner SID */
187 Sid = SepGetOwnerFromDescriptor(SecurityDescriptor);
188 ASSERT(Sid != NULL);
189
190 /* Lock the token if needed */
191 if (!TokenLocked) SepAcquireTokenLockShared(Token);
192
193 /* Check if the owner SID is found, handling restricted case as well */
194 Result = SepSidInToken(Token, Sid);
195 if ((Result) && (Token->TokenFlags & TOKEN_IS_RESTRICTED))
196 {
197 Result = SepSidInTokenEx(Token, NULL, Sid, FALSE, TRUE);
198 }
199
200 /* Release the lock if we had acquired it */
201 if (!TokenLocked) SepReleaseTokenLock(Token);
202
203 /* Return the result */
204 return Result;
205 }
206
207 /**
208 * @brief
209 * Retrieves token control information.
210 *
211 * @param[in] _Token
212 * A valid token object.
213 *
214 * @param[out] SecurityDescriptor
215 * The returned token control information.
216 *
217 * @return
218 * Nothing.
219 */
220 VOID
221 NTAPI
222 SeGetTokenControlInformation(
223 _In_ PACCESS_TOKEN _Token,
224 _Out_ PTOKEN_CONTROL TokenControl)
225 {
226 PTOKEN Token = _Token;
227 PAGED_CODE();
228
229 /* Capture the main fields */
230 TokenControl->AuthenticationId = Token->AuthenticationId;
231 TokenControl->TokenId = Token->TokenId;
232 TokenControl->TokenSource = Token->TokenSource;
233
234 /* Lock the token */
235 SepAcquireTokenLockShared(Token);
236
237 /* Capture the modified ID */
238 TokenControl->ModifiedId = Token->ModifiedId;
239
240 /* Unlock it */
241 SepReleaseTokenLock(Token);
242 }
243
244 /**
245 * @brief
246 * Creates a client security context based upon an access token.
247 *
248 * @param[in] Token
249 * A valid token object.
250 *
251 * @param[in] ClientSecurityQos
252 * The Quality of Service (QoS) of a client security context.
253 *
254 * @param[in] ServerIsRemote
255 * If the client is a remote server (TRUE), the function will retrieve the
256 * control information of an access token, that is, we're doing delegation
257 * and that the server isn't local.
258 *
259 * @param[in] TokenType
260 * Type of token.
261 *
262 * @param[in] ThreadEffectiveOnly
263 * If set to TRUE, the client wants that the current thread wants to modify
264 * (enable or disable) privileges and groups.
265 *
266 * @param[in] ImpersonationLevel
267 * Security impersonation level filled in the QoS context.
268 *
269 * @param[out] ClientContext
270 * The returned security client context.
271 *
272 * @return
273 * Returns STATUS_SUCCESS if client security creation has completed successfully.
274 * STATUS_INVALID_PARAMETER is returned if one or more of the parameters are bogus.
275 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the current impersonation level
276 * within QoS context doesn't meet with the conditions required. A failure
277 * NTSTATUS code is returned otherwise.
278 */
279 NTSTATUS
280 NTAPI
281 SepCreateClientSecurity(
282 _In_ PACCESS_TOKEN Token,
283 _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
284 _In_ BOOLEAN ServerIsRemote,
285 _In_ TOKEN_TYPE TokenType,
286 _In_ BOOLEAN ThreadEffectiveOnly,
287 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
288 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
289 {
290 NTSTATUS Status;
291 PACCESS_TOKEN NewToken;
292 PAGED_CODE();
293
294 /* Check for bogus impersonation level */
295 if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel))
296 {
297 /* Fail the call */
298 return STATUS_INVALID_PARAMETER;
299 }
300
301 /* Check what kind of token this is */
302 if (TokenType != TokenImpersonation)
303 {
304 /* On a primary token, if we do direct access, copy the flag from the QOS */
305 ClientContext->DirectAccessEffectiveOnly = ClientSecurityQos->EffectiveOnly;
306 }
307 else
308 {
309 /* This is an impersonation token, is the level ok? */
310 if (ClientSecurityQos->ImpersonationLevel > ImpersonationLevel)
311 {
312 /* Nope, fail */
313 return STATUS_BAD_IMPERSONATION_LEVEL;
314 }
315
316 /* Is the level too low, or are we doing something other than delegation remotely */
317 if ((ImpersonationLevel == SecurityAnonymous) ||
318 (ImpersonationLevel == SecurityIdentification) ||
319 ((ServerIsRemote) && (ImpersonationLevel != SecurityDelegation)))
320 {
321 /* Fail the call */
322 return STATUS_BAD_IMPERSONATION_LEVEL;
323 }
324
325 /* Pick either the thread setting or the QOS setting */
326 ClientContext->DirectAccessEffectiveOnly =
327 ((ThreadEffectiveOnly) || (ClientSecurityQos->EffectiveOnly)) ? TRUE : FALSE;
328 }
329
330 /* Is this static tracking */
331 if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
332 {
333 /* Do not use direct access and make a copy */
334 ClientContext->DirectlyAccessClientToken = FALSE;
335 Status = SeCopyClientToken(Token,
336 ClientSecurityQos->ImpersonationLevel,
337 KernelMode,
338 &NewToken);
339 if (!NT_SUCCESS(Status))
340 return Status;
341 }
342 else
343 {
344 /* Use direct access and check if this is local */
345 ClientContext->DirectlyAccessClientToken = TRUE;
346 if (ServerIsRemote)
347 {
348 /* We are doing delegation, so make a copy of the control data */
349 SeGetTokenControlInformation(Token,
350 &ClientContext->ClientTokenControl);
351 }
352
353 /* Keep the same token */
354 NewToken = Token;
355 }
356
357 /* Fill out the context and return success */
358 ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
359 ClientContext->SecurityQos.ImpersonationLevel = ClientSecurityQos->ImpersonationLevel;
360 ClientContext->SecurityQos.ContextTrackingMode = ClientSecurityQos->ContextTrackingMode;
361 ClientContext->SecurityQos.EffectiveOnly = ClientSecurityQos->EffectiveOnly;
362 ClientContext->ServerIsRemote = ServerIsRemote;
363 ClientContext->ClientToken = NewToken;
364 return STATUS_SUCCESS;
365 }
366
367 /* PUBLIC FUNCTIONS ***********************************************************/
368
369 /**
370 * @brief
371 * An extended function that captures the security subject context based upon
372 * the specified thread and process.
373 *
374 * @param[in] Thread
375 * A thread where the calling thread's token is to be referenced for
376 * the security context.
377 *
378 * @param[in] Process
379 * A process where the main process' token is to be referenced for
380 * the security context.
381 *
382 * @param[out] SubjectContext
383 * The returned security subject context.
384 *
385 * @return
386 * Nothing.
387 */
388 VOID
389 NTAPI
390 SeCaptureSubjectContextEx(
391 _In_ PETHREAD Thread,
392 _In_ PEPROCESS Process,
393 _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
394 {
395 BOOLEAN CopyOnOpen, EffectiveOnly;
396
397 PAGED_CODE();
398
399 /* Save the unique ID */
400 SubjectContext->ProcessAuditId = Process->UniqueProcessId;
401
402 /* Check if we have a thread */
403 if (!Thread)
404 {
405 /* We don't, so no token */
406 SubjectContext->ClientToken = NULL;
407 }
408 else
409 {
410 /* Get the impersonation token */
411 SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread,
412 &CopyOnOpen,
413 &EffectiveOnly,
414 &SubjectContext->ImpersonationLevel);
415 }
416
417 /* Get the primary token */
418 SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
419 }
420
421 /**
422 * @brief
423 * Captures the security subject context of the calling thread and calling
424 * process.
425 *
426 * @param[out] SubjectContext
427 * The returned security subject context.
428 *
429 * @return
430 * Nothing.
431 */
432 VOID
433 NTAPI
434 SeCaptureSubjectContext(
435 _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
436 {
437 /* Call the extended API */
438 SeCaptureSubjectContextEx(PsGetCurrentThread(),
439 PsGetCurrentProcess(),
440 SubjectContext);
441 }
442
443 /**
444 * @brief
445 * Locks both the referenced primary and client access tokens of a
446 * security subject context.
447 *
448 * @param[in] SubjectContext
449 * A valid security context with both referenced tokens.
450 *
451 * @return
452 * Nothing.
453 */
454 VOID
455 NTAPI
456 SeLockSubjectContext(
457 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
458 {
459 PTOKEN PrimaryToken, ClientToken;
460 PAGED_CODE();
461
462 /* Read both tokens */
463 PrimaryToken = SubjectContext->PrimaryToken;
464 ClientToken = SubjectContext->ClientToken;
465
466 /* Always lock the primary */
467 SepAcquireTokenLockShared(PrimaryToken);
468
469 /* Lock the impersonation one if it's there */
470 if (!ClientToken) return;
471 SepAcquireTokenLockShared(ClientToken);
472 }
473
474 /**
475 * @brief
476 * Unlocks both the referenced primary and client access tokens of a
477 * security subject context.
478 *
479 * @param[in] SubjectContext
480 * A valid security context with both referenced tokens.
481 *
482 * @return
483 * Nothing.
484 */
485 VOID
486 NTAPI
487 SeUnlockSubjectContext(
488 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
489 {
490 PTOKEN PrimaryToken, ClientToken;
491 PAGED_CODE();
492
493 /* Read both tokens */
494 PrimaryToken = SubjectContext->PrimaryToken;
495 ClientToken = SubjectContext->ClientToken;
496
497 /* Unlock the impersonation one if it's there */
498 if (ClientToken)
499 {
500 SepReleaseTokenLock(ClientToken);
501 }
502
503 /* Always unlock the primary one */
504 SepReleaseTokenLock(PrimaryToken);
505 }
506
507 /**
508 * @brief
509 * Releases both the primary and client tokens of a security
510 * subject context.
511 *
512 * @param[in] SubjectContext
513 * The captured security context.
514 *
515 * @return
516 * Nothing.
517 */
518 VOID
519 NTAPI
520 SeReleaseSubjectContext(
521 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
522 {
523 PAGED_CODE();
524
525 /* Drop reference on the primary */
526 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken);
527 SubjectContext->PrimaryToken = NULL;
528
529 /* Drop reference on the impersonation, if there was one */
530 PsDereferenceImpersonationToken(SubjectContext->ClientToken);
531 SubjectContext->ClientToken = NULL;
532 }
533
534 /**
535 * @brief
536 * An extended function that creates an access state.
537 *
538 * @param[in] Thread
539 * Valid thread object where subject context is to be captured.
540 *
541 * @param[in] Process
542 * Valid process object where subject context is to be captured.
543 *
544 * @param[in,out] AccessState
545 * An initialized returned parameter to an access state.
546 *
547 * @param[in] AuxData
548 * Auxiliary security data for access state.
549 *
550 * @param[in] Access
551 * Type of access mask to assign.
552 *
553 * @param[in] GenericMapping
554 * Generic mapping for the access state to assign.
555 *
556 * @return
557 * Returns STATUS_SUCCESS.
558 */
559 NTSTATUS
560 NTAPI
561 SeCreateAccessStateEx(
562 _In_ PETHREAD Thread,
563 _In_ PEPROCESS Process,
564 _Inout_ PACCESS_STATE AccessState,
565 _In_ PAUX_ACCESS_DATA AuxData,
566 _In_ ACCESS_MASK Access,
567 _In_ PGENERIC_MAPPING GenericMapping)
568 {
569 ACCESS_MASK AccessMask = Access;
570 PTOKEN Token;
571 PAGED_CODE();
572
573 /* Map the Generic Acess to Specific Access if we have a Mapping */
574 if ((Access & GENERIC_ACCESS) && (GenericMapping))
575 {
576 RtlMapGenericMask(&AccessMask, GenericMapping);
577 }
578
579 /* Initialize the Access State */
580 RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
581 ASSERT(AccessState->SecurityDescriptor == NULL);
582 ASSERT(AccessState->PrivilegesAllocated == FALSE);
583
584 /* Initialize and save aux data */
585 RtlZeroMemory(AuxData, sizeof(AUX_ACCESS_DATA));
586 AccessState->AuxData = AuxData;
587
588 /* Capture the Subject Context */
589 SeCaptureSubjectContextEx(Thread,
590 Process,
591 &AccessState->SubjectSecurityContext);
592
593 /* Set Access State Data */
594 AccessState->RemainingDesiredAccess = AccessMask;
595 AccessState->OriginalDesiredAccess = AccessMask;
596 ExAllocateLocallyUniqueId(&AccessState->OperationID);
597
598 /* Get the Token to use */
599 Token = SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext);
600
601 /* Check for Travers Privilege */
602 if (Token->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE)
603 {
604 /* Preserve the Traverse Privilege */
605 AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
606 }
607
608 /* Set the Auxiliary Data */
609 AuxData->PrivilegeSet = (PPRIVILEGE_SET)((ULONG_PTR)AccessState +
610 FIELD_OFFSET(ACCESS_STATE,
611 Privileges));
612 if (GenericMapping) AuxData->GenericMapping = *GenericMapping;
613
614 /* Return Sucess */
615 return STATUS_SUCCESS;
616 }
617
618 /**
619 * @brief
620 * Creates an access state.
621 *
622 * @param[in,out] AccessState
623 * An initialized returned parameter to an access state.
624 *
625 * @param[in] AuxData
626 * Auxiliary security data for access state.
627 *
628 * @param[in] Access
629 * Type of access mask to assign.
630 *
631 * @param[in] GenericMapping
632 * Generic mapping for the access state to assign.
633 *
634 * @return
635 * See SeCreateAccessStateEx.
636 */
637 NTSTATUS
638 NTAPI
639 SeCreateAccessState(
640 _Inout_ PACCESS_STATE AccessState,
641 _In_ PAUX_ACCESS_DATA AuxData,
642 _In_ ACCESS_MASK Access,
643 _In_ PGENERIC_MAPPING GenericMapping)
644 {
645 PAGED_CODE();
646
647 /* Call the extended API */
648 return SeCreateAccessStateEx(PsGetCurrentThread(),
649 PsGetCurrentProcess(),
650 AccessState,
651 AuxData,
652 Access,
653 GenericMapping);
654 }
655
656 /**
657 * @brief
658 * Deletes an allocated access state from the memory.
659 *
660 * @param[in] AccessState
661 * A valid access state.
662 *
663 * @return
664 * Nothing.
665 */
666 VOID
667 NTAPI
668 SeDeleteAccessState(
669 _In_ PACCESS_STATE AccessState)
670 {
671 PAUX_ACCESS_DATA AuxData;
672 PAGED_CODE();
673
674 /* Get the Auxiliary Data */
675 AuxData = AccessState->AuxData;
676
677 /* Deallocate Privileges */
678 if (AccessState->PrivilegesAllocated)
679 ExFreePoolWithTag(AuxData->PrivilegeSet, TAG_PRIVILEGE_SET);
680
681 /* Deallocate Name and Type Name */
682 if (AccessState->ObjectName.Buffer)
683 {
684 ExFreePool(AccessState->ObjectName.Buffer);
685 }
686
687 if (AccessState->ObjectTypeName.Buffer)
688 {
689 ExFreePool(AccessState->ObjectTypeName.Buffer);
690 }
691
692 /* Release the Subject Context */
693 SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
694 }
695
696 /**
697 * @brief
698 * Sets a new generic mapping for an allocated access state.
699 *
700 * @param[in] AccessState
701 * A valid access state.
702 *
703 * @param[in] GenericMapping
704 * New generic mapping to assign.
705 *
706 * @return
707 * Nothing.
708 */
709 VOID
710 NTAPI
711 SeSetAccessStateGenericMapping(
712 _In_ PACCESS_STATE AccessState,
713 _In_ PGENERIC_MAPPING GenericMapping)
714 {
715 PAGED_CODE();
716
717 /* Set the Generic Mapping */
718 ((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping;
719 }
720
721 /**
722 * @brief
723 * Creates a client security context.
724 *
725 * @param[in] Thread
726 * Thread object of the client where impersonation has to begin.
727 *
728 * @param[in] Qos
729 * Quality of service to specify what kind of impersonation to be done.
730 *
731 * @param[in] RemoteClient
732 * If set to TRUE, the client that we're going to impersonate is remote.
733 *
734 * @param[out] ClientContext
735 * The returned security client context.
736 *
737 * @return
738 * See SepCreateClientSecurity.
739 */
740 NTSTATUS
741 NTAPI
742 SeCreateClientSecurity(
743 _In_ PETHREAD Thread,
744 _In_ PSECURITY_QUALITY_OF_SERVICE Qos,
745 _In_ BOOLEAN RemoteClient,
746 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
747 {
748 TOKEN_TYPE TokenType;
749 BOOLEAN ThreadEffectiveOnly;
750 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
751 PACCESS_TOKEN Token;
752 NTSTATUS Status;
753 PAGED_CODE();
754
755 /* Reference the correct token */
756 Token = PsReferenceEffectiveToken(Thread,
757 &TokenType,
758 &ThreadEffectiveOnly,
759 &ImpersonationLevel);
760
761 /* Create client security from it */
762 Status = SepCreateClientSecurity(Token,
763 Qos,
764 RemoteClient,
765 TokenType,
766 ThreadEffectiveOnly,
767 ImpersonationLevel,
768 ClientContext);
769
770 /* Check if we failed or static tracking was used */
771 if (!(NT_SUCCESS(Status)) || (Qos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
772 {
773 /* Dereference our copy since it's not being used */
774 ObDereferenceObject(Token);
775 }
776
777 /* Return status */
778 return Status;
779 }
780
781 /**
782 * @brief
783 * Creates a client security context based upon the captured security
784 * subject context.
785 *
786 * @param[in] SubjectContext
787 * The captured subject context where client security is to be created
788 * from.
789 *
790 * @param[in] ClientSecurityQos
791 * Quality of service to specify what kind of impersonation to be done.
792 *
793 * @param[in] ServerIsRemote
794 * If set to TRUE, the client that we're going to impersonate is remote.
795 *
796 * @param[out] ClientContext
797 * The returned security client context.
798 *
799 * @return
800 * See SepCreateClientSecurity.
801 */
802 NTSTATUS
803 NTAPI
804 SeCreateClientSecurityFromSubjectContext(
805 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
806 _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
807 _In_ BOOLEAN ServerIsRemote,
808 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
809 {
810 PACCESS_TOKEN Token;
811 NTSTATUS Status;
812 PAGED_CODE();
813
814 /* Get the right token and reference it */
815 Token = SeQuerySubjectContextToken(SubjectContext);
816 ObReferenceObject(Token);
817
818 /* Create the context */
819 Status = SepCreateClientSecurity(Token,
820 ClientSecurityQos,
821 ServerIsRemote,
822 SubjectContext->ClientToken ?
823 TokenImpersonation : TokenPrimary,
824 FALSE,
825 SubjectContext->ImpersonationLevel,
826 ClientContext);
827
828 /* Check if we failed or static tracking was used */
829 if (!(NT_SUCCESS(Status)) ||
830 (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
831 {
832 /* Dereference our copy since it's not being used */
833 ObDereferenceObject(Token);
834 }
835
836 /* Return status */
837 return Status;
838 }
839
840 /**
841 * @brief
842 * Extended function that impersonates a client.
843 *
844 * @param[in] ClientContext
845 * A valid client context.
846 *
847 * @param[in] ServerThread
848 * The thread where impersonation is to be done.
849 *
850 * @return
851 * STATUS_SUCCESS is returned if the calling thread successfully impersonates
852 * the client. A failure NTSTATUS code is returned otherwise.
853 */
854 NTSTATUS
855 NTAPI
856 SeImpersonateClientEx(
857 _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
858 _In_opt_ PETHREAD ServerThread)
859 {
860 BOOLEAN EffectiveOnly;
861 PAGED_CODE();
862
863 /* Check if direct access is requested */
864 if (!ClientContext->DirectlyAccessClientToken)
865 {
866 /* No, so get the flag from QOS */
867 EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
868 }
869 else
870 {
871 /* Yes, so see if direct access should be effective only */
872 EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
873 }
874
875 /* Use the current thread if one was not passed */
876 if (!ServerThread) ServerThread = PsGetCurrentThread();
877
878 /* Call the lower layer routine */
879 return PsImpersonateClient(ServerThread,
880 ClientContext->ClientToken,
881 TRUE,
882 EffectiveOnly,
883 ClientContext->SecurityQos.ImpersonationLevel);
884 }
885
886 /**
887 * @brief
888 * Impersonates a client user.
889 *
890 * @param[in] ClientContext
891 * A valid client context.
892 *
893 * @param[in] ServerThread
894 * The thread where impersonation is to be done.
895 * *
896 * @return
897 * Nothing.
898 */
899 VOID
900 NTAPI
901 SeImpersonateClient(
902 _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
903 _In_opt_ PETHREAD ServerThread)
904 {
905 PAGED_CODE();
906
907 /* Call the new API */
908 SeImpersonateClientEx(ClientContext, ServerThread);
909 }
910
911 /* EOF */