ReactOS 0.4.15-dev-5669-g09dde2c
tokenadj.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for tokenadj.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

static NTSTATUS SepAdjustPrivileges (_Inout_ PTOKEN Token, _In_ BOOLEAN DisableAllPrivileges, _In_opt_ PLUID_AND_ATTRIBUTES NewState, _In_ ULONG NewStateCount, _Out_opt_ PTOKEN_PRIVILEGES PreviousState, _In_ BOOLEAN ApplyChanges, _Out_ PULONG ChangedPrivileges, _Out_ PBOOLEAN ChangesMade)
 Removes a certain amount of privileges of a token based upon the request by the caller.
 
static NTSTATUS SepAdjustGroups (_In_ PTOKEN Token, _In_opt_ PSID_AND_ATTRIBUTES NewState, _In_ ULONG NewStateCount, _In_ BOOLEAN ApplyChanges, _In_ BOOLEAN ResetToDefaultStates, _Out_ PBOOLEAN ChangesMade, _Out_opt_ PTOKEN_GROUPS PreviousGroupsState, _Out_ PULONG ChangedGroups)
 Private routine that iterates over the groups of an access token to be adjusted as per on request by the caller, where a group can be enabled or disabled.
 
_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtAdjustPrivilegesToken (_In_ HANDLE TokenHandle, _In_ BOOLEAN DisableAllPrivileges, _In_opt_ PTOKEN_PRIVILEGES NewState, _In_ ULONG BufferLength, _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
 Removes a certain amount of privileges of a token based upon the request by the caller.
 
NTSTATUS NTAPI NtAdjustGroupsToken (_In_ HANDLE TokenHandle, _In_ BOOLEAN ResetToDefault, _In_ PTOKEN_GROUPS NewState, _In_ ULONG BufferLength, _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState, _When_(PreviousState !=NULL, _Out_) PULONG ReturnLength)
 Changes the list of groups by enabling or disabling them in an access token. Unlike NtAdjustPrivilegesToken, this API routine does not remove groups.
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file tokenadj.c.

Function Documentation

◆ NtAdjustGroupsToken()

NTSTATUS NTAPI NtAdjustGroupsToken ( _In_ HANDLE  TokenHandle,
_In_ BOOLEAN  ResetToDefault,
_In_ PTOKEN_GROUPS  NewState,
_In_ ULONG  BufferLength,
_Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS  PreviousState,
_When_(PreviousState !=NULL, _Out_) PULONG  ReturnLength 
)

Changes the list of groups by enabling or disabling them in an access token. Unlike NtAdjustPrivilegesToken, this API routine does not remove groups.

Parameters
[in]TokenHandleToken handle where the list of groups SID are to be adjusted. The access token must have TOKEN_ADJUST_GROUPS access right in order to change the groups in a token. The token must also have TOKEN_QUERY access right if the caller requests the previous states of groups list, that is, PreviousState is not NULL.
[in]ResetToDefaultIf set to TRUE, the function resets the list of groups to default enabled and disabled states. NewState is ignored in this case. Otherwise if the parameter is set to FALSE, the function expects a new list of groups from NewState to be adjusted within the token.
[in]NewStateA new list of groups SID that the function will use it accordingly to modify the current list of groups SID of a token.
[in]BufferLengthThe length size of the buffer that is pointed by the NewState parameter argument, in bytes.
[out]PreviousStateIf specified, the function will return to the caller the old list of groups SID. If this parameter is NULL, ReturnLength must also be NULL.
[out]ReturnLengthIf specified, the function will return the total size length of the old list of groups SIDs, in bytes.
Returns
STATUS_SUCCESS is returned if the function has successfully adjusted the token's groups. STATUS_INVALID_PARAMETER is returned if the caller has submitted one or more invalid parameters, that is, the caller didn't want to reset the groups to default state but no NewState argument list has been provided. STATUS_BUFFER_TOO_SMALL is returned if the buffer length given by the caller is smaller than the required length size. A failure NTSTATUS code is returned otherwise.

Definition at line 695 of file tokenadj.c.

703{
707 ULONG ChangeCount, RequiredLength;
708 ULONG CapturedCount = 0;
709 ULONG CapturedLength = 0;
710 ULONG NewStateSize = 0;
711 PSID_AND_ATTRIBUTES CapturedGroups = NULL;
712 BOOLEAN ChangesMade = FALSE;
713
714 PAGED_CODE();
715
716 /*
717 * If the caller doesn't want to reset the groups of an
718 * access token to default states then at least we must
719 * expect a list of groups to be adjusted based on NewState
720 * parameter. Otherwise bail out because the caller has
721 * no idea what they're doing.
722 */
723 if (!ResetToDefault && !NewState)
724 {
725 DPRINT1("NtAdjustGroupsToken(): The caller hasn't provided any list of groups to adjust!\n");
727 }
728
730
732 {
734 {
735 /* Probe NewState */
736 if (!ResetToDefault)
737 {
738 /* Probe the header */
739 ProbeForRead(NewState, sizeof(*NewState), sizeof(ULONG));
740
741 CapturedCount = NewState->GroupCount;
742 NewStateSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedCount]);
743
744 ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
745 }
746
747 if (PreviousState != NULL)
748 {
750 ProbeForWrite(ReturnLength, sizeof(*ReturnLength), sizeof(ULONG));
751 }
752 }
754 {
755 /* Return the exception code */
757 }
758 _SEH2_END;
759 }
760 else
761 {
762 /*
763 * We're calling directly from the kernel, just retrieve
764 * the number count of captured groups outright.
765 */
766 if (!ResetToDefault)
767 {
768 CapturedCount = NewState->GroupCount;
769 }
770 }
771
772 /* Time to capture the NewState list */
773 if (!ResetToDefault)
774 {
776 {
777 Status = SeCaptureSidAndAttributesArray(NewState->Groups,
778 CapturedCount,
780 NULL,
781 0,
782 PagedPool,
783 TRUE,
784 &CapturedGroups,
785 &CapturedLength);
786 }
788 {
790 }
791 _SEH2_END;
792
793 if (!NT_SUCCESS(Status))
794 {
795 DPRINT1("NtAdjustGroupsToken(): Failed to capture the NewState list of groups (Status 0x%lx)\n", Status);
796 return Status;
797 }
798 }
799
800 /* Time to reference the token */
805 (PVOID*)&Token,
806 NULL);
807 if (!NT_SUCCESS(Status))
808 {
809 /* We couldn't reference the access token, bail out */
810 DPRINT1("NtAdjustGroupsToken(): Failed to reference the token (Status 0x%lx)\n", Status);
811
812 if (CapturedGroups != NULL)
813 {
814 SeReleaseSidAndAttributesArray(CapturedGroups,
816 TRUE);
817 }
818
819 return Status;
820 }
821
822 /* Lock the token */
824
825 /* Count the number of groups to be changed */
827 CapturedGroups,
828 CapturedCount,
829 FALSE,
830 ResetToDefault,
831 &ChangesMade,
832 NULL,
833 &ChangeCount);
834
835 /* Does the caller want the previous state of groups? */
836 if (PreviousState != NULL)
837 {
838 /* Calculate the required length */
839 RequiredLength = FIELD_OFFSET(TOKEN_GROUPS, Groups[ChangeCount]);
840
841 /* Return the required length to the caller */
843 {
845 }
847 {
848 /* Bail out and return the exception code */
850 _SEH2_YIELD(goto Quit);
851 }
852 _SEH2_END;
853
854 /* The buffer length provided is smaller than the required length, bail out */
856 {
858 goto Quit;
859 }
860 }
861
862 /*
863 * Now it's time to apply changes. Wrap the code
864 * in SEH as we are returning the old groups state
865 * list to the caller since PreviousState is a
866 * UM pointer.
867 */
869 {
871 CapturedGroups,
872 CapturedCount,
873 TRUE,
874 ResetToDefault,
875 &ChangesMade,
877 &ChangeCount);
878 }
880 {
881 /* Bail out and return the exception code */
883
884 /* Force the write as we touched the token still */
885 ChangesMade = TRUE;
886 _SEH2_YIELD(goto Quit);
887 }
888 _SEH2_END;
889
890Quit:
891 /* Allocate a new ID for the token as we made changes */
892 if (ChangesMade)
893 ExAllocateLocallyUniqueId(&Token->ModifiedId);
894
895 /* Unlock and dereference the token */
898
899 /* Release the captured groups */
900 if (CapturedGroups != NULL)
901 {
902 SeReleaseSidAndAttributesArray(CapturedGroups,
904 TRUE);
905 }
906
907 return Status;
908}
#define PAGED_CODE()
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
#define PagedPool
Definition: env_spec_w32.h:308
#define ExGetPreviousMode
Definition: ex.h:139
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define KernelMode
Definition: asm.h:34
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:718
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
VOID NTAPI SeReleaseSidAndAttributesArray(_In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID with attributes.
Definition: sid.c:994
#define SepAcquireTokenLockExclusive(Token)
Definition: se.h:275
NTSTATUS NTAPI SeCaptureSidAndAttributesArray(_In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes, _In_ ULONG AttributeCount, _In_ KPROCESSOR_MODE PreviousMode, _In_opt_ PVOID AllocatedMem, _In_ ULONG AllocatedLength, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes, _Out_ PULONG ResultLength)
Captures a SID with attributes.
Definition: sid.c:711
#define SepReleaseTokenLock(Token)
Definition: se.h:286
POBJECT_TYPE SeTokenObjectType
Definition: token.c:17
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
static NTSTATUS SepAdjustGroups(_In_ PTOKEN Token, _In_opt_ PSID_AND_ATTRIBUTES NewState, _In_ ULONG NewStateCount, _In_ BOOLEAN ApplyChanges, _In_ BOOLEAN ResetToDefaultStates, _Out_ PBOOLEAN ChangesMade, _Out_opt_ PTOKEN_GROUPS PreviousGroupsState, _Out_ PULONG ChangedGroups)
Private routine that iterates over the groups of an access token to be adjusted as per on request by ...
Definition: tokenadj.c:246
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDF_POWER_DEVICE_STATE PreviousState
Definition: wdfdevice.h:829
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_In_ ULONG _Out_opt_ PULONG RequiredLength
Definition: wmifuncs.h:30
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define ObDereferenceObject
Definition: obfuncs.h:203
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
#define TOKEN_QUERY
Definition: setypes.h:924
#define TOKEN_ADJUST_GROUPS
Definition: setypes.h:927

Referenced by AdjustTokenGroups(), and START_TEST().

◆ NtAdjustPrivilegesToken()

_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtAdjustPrivilegesToken ( _In_ HANDLE  TokenHandle,
_In_ BOOLEAN  DisableAllPrivileges,
_In_opt_ PTOKEN_PRIVILEGES  NewState,
_In_ ULONG  BufferLength,
_Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES  PreviousState,
_When_(PreviousState!=NULL, _Out_) PULONG  ReturnLength 
)

Removes a certain amount of privileges of a token based upon the request by the caller.

Parameters
[in,out]TokenToken handle where the privileges are about to be modified.
[in]DisableAllPrivilegesIf set to TRUE, the function disables all the privileges.
[in]NewStateA new list of privileges that the function will use it accordingly to either disable or enable the said privileges and change them.
[in]NewStateCountThe new total number count of privileges.
[out]PreviousStateIf specified, the function will return the previous state list of privileges.
[in]ApplyChangesIf set to TRUE, the function will immediatelly apply the changes onto the token's privileges.
[out]ChangedPrivilegesThe returned count number of changed privileges.
[out]ChangesMadeIf TRUE, the function has made changes to the token's privileges. FALSE otherwise.
Returns
Returns STATUS_SUCCESS if the function has successfully changed the list of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege has been changed.

Definition at line 451 of file tokenadj.c.

459{
463 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
464 ULONG CapturedCount = 0;
465 ULONG CapturedLength = 0;
466 ULONG NewStateSize = 0;
467 ULONG ChangeCount;
469 BOOLEAN ChangesMade = FALSE;
470
471 PAGED_CODE();
472
473 DPRINT("NtAdjustPrivilegesToken() called\n");
474
475 /* Fail, if we do not disable all privileges but NewState is NULL */
476 if (DisableAllPrivileges == FALSE && NewState == NULL)
478
481 {
483 {
484 /* Probe NewState */
485 if (DisableAllPrivileges == FALSE)
486 {
487 /* First probe the header */
488 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
489
490 CapturedCount = NewState->PrivilegeCount;
491 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
492
493 ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
494 }
495
496 /* Probe PreviousState and ReturnLength */
497 if (PreviousState != NULL)
498 {
500 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
501 }
502 }
504 {
505 /* Return the exception code */
507 }
508 _SEH2_END;
509 }
510 else
511 {
512 /* This is kernel mode, we trust the caller */
513 if (DisableAllPrivileges == FALSE)
514 CapturedCount = NewState->PrivilegeCount;
515 }
516
517 /* Do we need to capture the new state? */
518 if (DisableAllPrivileges == FALSE)
519 {
521 {
522 /* Capture the new state array of privileges */
523 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
524 CapturedCount,
526 NULL,
527 0,
528 PagedPool,
529 TRUE,
530 &CapturedPrivileges,
531 &CapturedLength);
532 }
534 {
535 /* Return the exception code */
537 }
538 _SEH2_END;
539
540 if (!NT_SUCCESS(Status))
541 return Status;
542 }
543
544 /* Reference the token */
549 (PVOID*)&Token,
550 NULL);
551 if (!NT_SUCCESS(Status))
552 {
553 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
554
555 /* Release the captured privileges */
556 if (CapturedPrivileges != NULL)
557 {
558 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
560 TRUE);
561 }
562
563 return Status;
564 }
565
566 /* Lock the token */
568
569 /* Count the privileges that need to be changed, do not apply them yet */
571 DisableAllPrivileges,
572 CapturedPrivileges,
573 CapturedCount,
574 NULL,
575 FALSE,
576 &ChangeCount,
577 &ChangesMade);
578
579 /* Check if the caller asked for the previous state */
580 if (PreviousState != NULL)
581 {
582 /* Calculate the required length */
584
585 /* Try to return the required buffer length */
587 {
589 }
591 {
592 /* Do cleanup and return the exception code */
594 _SEH2_YIELD(goto Cleanup);
595 }
596 _SEH2_END;
597
598 /* Fail, if the buffer length is smaller than the required length */
600 {
602 goto Cleanup;
603 }
604 }
605
606 /* Now enter SEH, since we might return the old privileges */
608 {
609 /* This time apply the changes */
611 DisableAllPrivileges,
612 CapturedPrivileges,
613 CapturedCount,
615 TRUE,
616 &ChangeCount,
617 &ChangesMade);
618 }
620 {
621 /* Do cleanup and return the exception code */
623 ChangesMade = TRUE; // Force write.
624 _SEH2_YIELD(goto Cleanup);
625 }
626 _SEH2_END;
627
628Cleanup:
629 /* Touch the token if we made changes */
630 if (ChangesMade)
631 ExAllocateLocallyUniqueId(&Token->ModifiedId);
632
633 /* Unlock and dereference the token */
636
637 /* Release the captured privileges */
638 if (CapturedPrivileges != NULL)
639 {
640 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
642 TRUE);
643 }
644
645 DPRINT("NtAdjustPrivilegesToken() done\n");
646 return Status;
647}
static const WCHAR Cleanup[]
Definition: register.c:80
#define KeGetPreviousMode()
Definition: ketypes.h:1108
VOID NTAPI SeReleaseLuidAndAttributesArray(_In_ PLUID_AND_ATTRIBUTES Privilege, _In_ KPROCESSOR_MODE PreviousMode, _In_ BOOLEAN CaptureIfKernel)
Releases a LUID with attributes structure.
Definition: priv.c:554
NTSTATUS NTAPI SeCaptureLuidAndAttributesArray(_In_ PLUID_AND_ATTRIBUTES Src, _In_ ULONG PrivilegeCount, _In_ KPROCESSOR_MODE PreviousMode, _In_ PLUID_AND_ATTRIBUTES AllocatedMem, _In_ ULONG AllocatedLength, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PLUID_AND_ATTRIBUTES *Dest, _Inout_ PULONG Length)
#define DPRINT
Definition: sndvol32.h:71
static NTSTATUS SepAdjustPrivileges(_Inout_ PTOKEN Token, _In_ BOOLEAN DisableAllPrivileges, _In_opt_ PLUID_AND_ATTRIBUTES NewState, _In_ ULONG NewStateCount, _Out_opt_ PTOKEN_PRIVILEGES PreviousState, _In_ BOOLEAN ApplyChanges, _Out_ PULONG ChangedPrivileges, _Out_ PBOOLEAN ChangesMade)
Removes a certain amount of privileges of a token based upon the request by the caller.
Definition: tokenadj.c:56
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET * Privileges
Definition: sefuncs.h:17
#define TOKEN_ADJUST_PRIVILEGES
Definition: setypes.h:926

Referenced by AdjustEnableDefaultPriv(), AdjustTokenPrivileges(), SmpAcquirePrivilege(), and SmpReleasePrivilege().

◆ SepAdjustGroups()

static NTSTATUS SepAdjustGroups ( _In_ PTOKEN  Token,
_In_opt_ PSID_AND_ATTRIBUTES  NewState,
_In_ ULONG  NewStateCount,
_In_ BOOLEAN  ApplyChanges,
_In_ BOOLEAN  ResetToDefaultStates,
_Out_ PBOOLEAN  ChangesMade,
_Out_opt_ PTOKEN_GROUPS  PreviousGroupsState,
_Out_ PULONG  ChangedGroups 
)
static

Private routine that iterates over the groups of an access token to be adjusted as per on request by the caller, where a group can be enabled or disabled.

Parameters
[in]TokenAccess token where its groups are to be enabled or disabled.
[in]NewStateA list of groups with new state attributes to be assigned to the token.
[in]NewStateCountThe captured count number of groups in the list.
[in]ApplyChangesIf set to FALSE, the function will only iterate over the token's groups without performing any kind of modification. If set to TRUE, the changes will be applied immediately when the function has done looping the groups.
[in]ResetToDefaultStatesThe function will reset the groups in an access token to default states if set to TRUE. In such scenario the function ignores NewState outright. Otherwise if set to FALSE, the function will use NewState to assign the newly attributes to adjust the token's groups. SE_GROUP_ENABLED_BY_DEFAULT is a flag indicator that is used for such purpose.
[out]ChangesMadeReturns TRUE if changes to token's groups have been made, otherwise FALSE is returned. Bear in mind such changes aren't always deterministic. See remarks for further details.
[out]PreviousGroupsStateIf requested by the caller, the function will return the previous state of groups in an access token prior taking action on adjusting the token. This is a UM (user mode) pointer and it's prone to raise exceptions if such pointer address is not valid.
[out]ChangedGroupsReturns the total number of changed groups in an access token. This argument could also indicate the number of groups to be changed if the calling thread hasn't chosen to apply the changes yet. A number of 0 indicates no groups have been or to be changed because the groups' attributes in a token are the same as the ones from NewState given by the caller.
Returns
STATUS_SUCCESS is returned if the function has successfully completed the operation of adjusting groups in a token. STATUS_CANT_DISABLE_MANDATORY is returned if there was an attempt to disable a mandatory group which is not possible. STATUS_CANT_ENABLE_DENY_ONLY is returned if there was an attempt to enable a "use for Deny only" group which is not allowed, that is, a restricted group. STATUS_NOT_ALL_ASSIGNED is returned if not all the groups are actually assigned to the token.
Remarks
Token groups adjusting can be judged to be deterministic or not based on the NT status code value. That is, STATUS_SUCCESS indicates the function not only has iterated over the whole groups in a token, it also has applied the changes thoroughly without impediment and the results perfectly match with the request desired by the caller. In this situation the condition is deemed deterministic. In a different situation however, if the status code was STATUS_NOT_ALL_ASSIGNED, the function would still continue looping the groups in a token and apply the changes whenever possible where the respective groups actually exist in the token. This kind of situation is deemed as indeterministic. For STATUS_CANT_DISABLE_MANDATORY and STATUS_CANT_ENABLE_DENY_ONLY the scenario is even more indeterministic as the iteration of groups comes to a halt thus leaving all other possible groups to be adjusted.

Definition at line 246 of file tokenadj.c.

255{
256 ULONG GroupsInToken, GroupsInList;
257 ULONG ChangeCount, GroupsCount, NewAttributes;
258
259 PAGED_CODE();
260
261 /* Ensure that the token we get is valid */
262 ASSERT(Token);
263
264 /* Initialize the counters and begin the work */
265 *ChangesMade = FALSE;
266 GroupsCount = 0;
267 ChangeCount = 0;
268
269 /* Begin looping all the groups in the token */
270 for (GroupsInToken = 0; GroupsInToken < Token->UserAndGroupCount; GroupsInToken++)
271 {
272 /* Does the caller want to reset groups to default states? */
273 if (ResetToDefaultStates)
274 {
275 /*
276 * SE_GROUP_ENABLED_BY_DEFAULT is a special indicator that informs us
277 * if a certain group has been enabled by default or not. In case
278 * a group is enabled by default but it is not currently enabled then
279 * at that point we must enable it back by default. For now just
280 * assign the respective SE_GROUP_ENABLED attribute as we'll do the
281 * eventual work later.
282 */
283 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) &&
284 (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED) == 0)
285 {
286 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_ENABLED;
287 }
288
289 /*
290 * Unlike the case above, a group that hasn't been enabled by
291 * default but it's currently enabled then we must disable
292 * it back.
293 */
294 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) == 0 &&
295 (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED))
296 {
297 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
298 }
299 }
300 else
301 {
302 /* Loop the provided groups in the list then */
303 for (GroupsInList = 0; GroupsInList < NewStateCount; GroupsInList++)
304 {
305 /* Does this group exist in the token? */
306 if (RtlEqualSid(&Token->UserAndGroups[GroupsInToken].Sid,
307 &NewState[GroupsInList].Sid))
308 {
309 /*
310 * This is the group that we're looking for.
311 * However, it could be that the group is a
312 * mandatory group which we are not allowed
313 * and cannot disable it.
314 */
315 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_MANDATORY) &&
316 (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED) == 0)
317 {
318 /* It is mandatory, forget about this group */
319 DPRINT1("SepAdjustGroups(): The SID group is mandatory!\n");
321 }
322
323 /*
324 * We've to ensure that apart the group mustn't be
325 * mandatory, it mustn't be a restricted group as
326 * well. That is, the group is marked with
327 * SE_GROUP_USE_FOR_DENY_ONLY flag and no one
328 * can enable it because it's for "deny" use only.
329 */
330 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) &&
331 (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED))
332 {
333 /* This group is restricted, forget about it */
334 DPRINT1("SepAdjustGroups(): The SID group is for use deny only!\n");
336 }
337
338 /* Copy the attributes and stop searching */
339 NewAttributes = NewState[GroupsInList].Attributes;
340 NewAttributes &= SE_GROUP_ENABLED;
341 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
342 break;
343 }
344
345 /* Did we find the specific group we wanted? */
346 if (GroupsInList == NewStateCount)
347 {
348 /* We didn't, continue with the next token's group */
349 continue;
350 }
351 }
352
353 /* Count the group that we found it */
354 GroupsCount++;
355
356 /* Does the token have the same attributes as the caller requested them? */
357 if (Token->UserAndGroups[GroupsInToken].Attributes != NewAttributes)
358 {
359 /*
360 * No, then it's time to make some adjustment to the
361 * token's groups. Does the caller want the previous states
362 * of groups?
363 */
364 if (PreviousGroupsState != NULL)
365 {
366 PreviousGroupsState->Groups[ChangeCount] = Token->UserAndGroups[GroupsInToken];
367 }
368
369 /* Time to apply the changes now? */
370 if (ApplyChanges)
371 {
372 /* The caller gave us consent, apply and report that we made changes! */
373 Token->UserAndGroups[GroupsInToken].Attributes = NewAttributes;
374 *ChangesMade = TRUE;
375 }
376
377 /* Increment the count change */
378 ChangeCount++;
379 }
380 }
381 }
382
383 /* Report the number of previous saved groups */
384 if (PreviousGroupsState != NULL)
385 {
386 PreviousGroupsState->GroupCount = ChangeCount;
387 }
388
389 /* Report the number of changed groups */
390 *ChangedGroups = ChangeCount;
391
392 /* Did we miss some groups? */
393 if (!ResetToDefaultStates && (GroupsCount < NewStateCount))
394 {
395 /*
396 * If we're at this stage then we are in a situation
397 * where the adjust changes done to token's groups is
398 * not deterministic as the caller might have wanted
399 * as per NewState parameter.
400 */
401 DPRINT1("SepAdjustGroups(): The token hasn't all the groups assigned!\n");
403 }
404
405 return STATUS_SUCCESS;
406}
#define ASSERT(a)
Definition: mode.c:44
NTSYSAPI BOOLEAN NTAPI RtlEqualSid(_In_ PSID Sid1, _In_ PSID Sid2)
#define SE_GROUP_USE_FOR_DENY_ONLY
Definition: setypes.h:94
#define SE_GROUP_MANDATORY
Definition: setypes.h:90
#define SE_GROUP_ENABLED_BY_DEFAULT
Definition: setypes.h:91
#define SE_GROUP_ENABLED
Definition: setypes.h:92
#define STATUS_NOT_ALL_ASSIGNED
Definition: ntstatus.h:85
#define STATUS_CANT_DISABLE_MANDATORY
Definition: ntstatus.h:329
#define STATUS_CANT_ENABLE_DENY_ONLY
Definition: ntstatus.h:806
#define STATUS_SUCCESS
Definition: shellext.h:65
BOOL ApplyChanges(HWND hwndDlg)
Definition: sounds.c:1014

Referenced by NtAdjustGroupsToken().

◆ SepAdjustPrivileges()

static NTSTATUS SepAdjustPrivileges ( _Inout_ PTOKEN  Token,
_In_ BOOLEAN  DisableAllPrivileges,
_In_opt_ PLUID_AND_ATTRIBUTES  NewState,
_In_ ULONG  NewStateCount,
_Out_opt_ PTOKEN_PRIVILEGES  PreviousState,
_In_ BOOLEAN  ApplyChanges,
_Out_ PULONG  ChangedPrivileges,
_Out_ PBOOLEAN  ChangesMade 
)
static

Removes a certain amount of privileges of a token based upon the request by the caller.

Parameters
[in,out]TokenToken handle where the privileges are about to be modified.
[in]DisableAllPrivilegesIf set to TRUE, the function disables all the privileges.
[in]NewStateA new list of privileges that the function will use it accordingly to either disable or enable the said privileges and change them.
[in]NewStateCountThe new total number count of privileges.
[out]PreviousStateIf specified, the function will return the previous state list of privileges.
[in]ApplyChangesIf set to TRUE, the function will immediatelly apply the changes onto the token's privileges.
[out]ChangedPrivilegesThe returned count number of changed privileges.
[out]ChangesMadeIf TRUE, the function has made changes to the token's privileges. FALSE otherwise.
Returns
Returns STATUS_SUCCESS if the function has successfully changed the list of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege has been changed.

Definition at line 56 of file tokenadj.c.

65{
66 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
67
68 PAGED_CODE();
69
70 /* Count the found privileges and those that need to be changed */
71 PrivilegeCount = 0;
72 ChangeCount = 0;
73 *ChangesMade = FALSE;
74
75 /* Loop all privileges in the token */
76 for (i = 0; i < Token->PrivilegeCount; i++)
77 {
78 /* Shall all of them be disabled? */
79 if (DisableAllPrivileges)
80 {
81 /* The new attributes are the old ones, but disabled */
82 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
83 }
84 else
85 {
86 /* Otherwise loop all provided privileges */
87 for (j = 0; j < NewStateCount; j++)
88 {
89 /* Check if this is the LUID we are looking for */
90 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
91 {
92 DPRINT("Found privilege\n");
93
94 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
95 NewAttributes = NewState[j].Attributes;
96 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
97 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
98
99 /* Stop looking */
100 break;
101 }
102 }
103
104 /* Check if we didn't find the privilege */
105 if (j == NewStateCount)
106 {
107 /* Continue with the token's next privilege */
108 continue;
109 }
110 }
111
112 /* We found a privilege, count it */
113 PrivilegeCount++;
114
115 /* Does the privilege need to be changed? */
116 if (Token->Privileges[i].Attributes != NewAttributes)
117 {
118 /* Does the caller want the old privileges? */
119 if (PreviousState != NULL)
120 {
121 /* Copy the old privilege */
122 PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
123 }
124
125 /* Does the caller want to apply the changes? */
126 if (ApplyChanges)
127 {
128 /* Shall we remove the privilege? */
129 if (NewAttributes & SE_PRIVILEGE_REMOVED)
130 {
131 /* Set the token as disabled and update flags for it */
132 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
134
135 /* Remove the privilege */
137
138 *ChangesMade = TRUE;
139
140 /* Fix the running index and continue with next one */
141 i--;
142 continue;
143 }
144
145 /* Set the new attributes and update flags */
146 Token->Privileges[i].Attributes = NewAttributes;
148 *ChangesMade = TRUE;
149 }
150
151 /* Increment the change count */
152 ChangeCount++;
153 }
154 }
155
156 /* Set the number of saved privileges */
157 if (PreviousState != NULL)
158 PreviousState->PrivilegeCount = ChangeCount;
159
160 /* Return the number of changed privileges */
161 *ChangedPrivileges = ChangeCount;
162
163 /* Check if we missed some */
164 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
165 {
167 }
168
169 return STATUS_SUCCESS;
170}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
VOID SepRemovePrivilegeToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a privilege from the token.
Definition: token.c:582
VOID SepUpdateSinglePrivilegeFlagToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Updates the token's flags based upon the privilege that the token has been granted....
Definition: token.c:442
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
#define SE_PRIVILEGE_REMOVED
Definition: setypes.h:64

Referenced by NtAdjustPrivilegesToken().