Пример #1
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
    PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
    PSID Owner, Group;
    PACL Sacl, Dacl;
    PAGED_CODE_RTL();

    _SEH2_TRY
    {
        /* Fail on bad revisions */
        if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return FALSE;

        /* Owner SID must be valid if present */
        Owner = SepGetOwnerFromDescriptor(Sd);
        if ((Owner) && (!RtlValidSid(Owner))) return FALSE;

        /* Group SID must be valid if present */
        Group = SepGetGroupFromDescriptor(Sd);
        if ((Owner) && (!RtlValidSid(Group))) return FALSE;

        /* DACL must be valid if present */
        Dacl = SepGetDaclFromDescriptor(Sd);
        if ((Dacl) && (!RtlValidAcl(Dacl))) return FALSE;

        /* SACL must be valid if present */
        Sacl = SepGetSaclFromDescriptor(Sd);
        if ((Sacl) && (!RtlValidAcl(Sacl))) return FALSE;
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Access fault, bail out */
        return FALSE;
    }
    _SEH2_END;

    /* All good */
    return TRUE;
}
Пример #2
0
/**************************************************************************
 *                 RtlFirstFreeAce			[NTDLL.@]
 * looks for the AceCount+1 ACE, and if it is still within the alloced
 * ACL, return a pointer to it
 */
BOOLEAN WINAPI RtlFirstFreeAce(
	PACL acl,
	PACE_HEADER* x)
{
	PACE_HEADER	ace;
	int		i;

	*x = 0;
	if(!RtlValidAcl(acl)) return FALSE;

	ace = (PACE_HEADER)(acl+1);
	for (i=0;i<acl->AceCount;i++) {
		if ((DWORD)ace>=(((DWORD)acl)+acl->AclSize)) break;
		ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
	}

	/* x should be non null if ACL is valid but there isn't a free ace */
	*x = ace;
	if ((DWORD)ace>=(((DWORD)acl)+acl->AclSize))
		return FALSE;
	return TRUE;
}
Пример #3
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
RtlValidRelativeSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
                                   IN ULONG SecurityDescriptorLength,
                                   IN SECURITY_INFORMATION RequiredInformation)
{
    PISECURITY_DESCRIPTOR_RELATIVE Sd = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptorInput;
    PSID Owner, Group;
    PACL Dacl, Sacl;
    ULONG Length;
    PAGED_CODE_RTL();

    /* Note that Windows allows no DACL/SACL even if RequiredInfo wants it */

    /* Do we have enough space, is the revision vaild, and is this SD relative? */
    if ((SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) ||
        (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) ||
        !(Sd->Control & SE_SELF_RELATIVE))
    {
        /* Nope, bail out */
        return FALSE;
    }

    /* Is there an owner? */
    if (Sd->Owner)
    {
        /* Try to access it */
        if (!RtlpValidateSDOffsetAndSize(Sd->Owner,
                                         SecurityDescriptorLength,
                                         sizeof(SID),
                                         &Length))
        {
            /* It's beyond the buffer, fail */
            return FALSE;
        }

        /* Read the owner, check if it's valid and if the buffer contains it */
        Owner = (PSID)((ULONG_PTR)Sd->Owner + (ULONG_PTR)Sd);
        if (!RtlValidSid(Owner) || (Length < RtlLengthSid(Owner))) return FALSE;
    }
    else if (RequiredInformation & OWNER_SECURITY_INFORMATION)
    {
        /* No owner but the caller expects one, fail */
        return FALSE;
    }

    /* Is there a group? */
    if (Sd->Group)
    {
        /* Try to access it */
        if (!RtlpValidateSDOffsetAndSize(Sd->Group,
                                         SecurityDescriptorLength,
                                         sizeof(SID),
                                         &Length))
        {
            /* It's beyond the buffer, fail */
            return FALSE;
        }

        /* Read the group, check if it's valid and if the buffer contains it */
        Group = (PSID)((ULONG_PTR)Sd->Group + (ULONG_PTR)Sd);
        if (!RtlValidSid(Group) || (Length < RtlLengthSid(Group))) return FALSE;
    }
    else if (RequiredInformation & GROUP_SECURITY_INFORMATION)
    {
        /* No group, but the caller expects one, fail */
        return FALSE;
    }

    /* Is there a DACL? */
    if ((Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT)
    {
        /* Try to access it */
        if (!RtlpValidateSDOffsetAndSize(Sd->Dacl,
                                         SecurityDescriptorLength,
                                         sizeof(ACL),
                                         &Length))
        {
            /* It's beyond the buffer, fail */
            return FALSE;
        }

        /* Read the DACL, check if it's valid and if the buffer contains it */
        Dacl = (PSID)((ULONG_PTR)Sd->Dacl + (ULONG_PTR)Sd);
        if (!(RtlValidAcl(Dacl)) || (Length < Dacl->AclSize)) return FALSE;
    }

    /* Is there a SACL? */
    if ((Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT)
    {
        /* Try to access it */
        if (!RtlpValidateSDOffsetAndSize(Sd->Sacl,
                                         SecurityDescriptorLength,
                                         sizeof(ACL),
                                         &Length))
        {
            /* It's beyond the buffer, fail */
            return FALSE;
        }

        /* Read the SACL, check if it's valid and if the buffer contains it */
        Sacl = (PSID)((ULONG_PTR)Sd->Sacl + (ULONG_PTR)Sd);
        if (!(RtlValidAcl(Sacl)) || (Length < Sacl->AclSize)) return FALSE;
    }

    /* All good */
    return TRUE;
}
Пример #4
0
NTSTATUS
NTAPI
RtlpAddKnownAce(IN PACL Acl,
                IN ULONG Revision,
                IN ULONG Flags,
                IN ACCESS_MASK AccessMask,
                IN PSID Sid,
                IN UCHAR Type)
{
    PKNOWN_ACE Ace;
    ULONG AceSize, InvalidFlags;
    PAGED_CODE_RTL();

    /* Check the validity of the SID */
    if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;

    /* Check the validity of the revision */
    if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4))
    {
        return STATUS_REVISION_MISMATCH;
    }

    /* Pick the smallest of the revisions */
    if (Revision < Acl->AclRevision) Revision = Acl->AclRevision;

    /* Validate the flags */
    if (Type == SYSTEM_AUDIT_ACE_TYPE)
    {
        InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS |
                                 SUCCESSFUL_ACCESS_ACE_FLAG |
                                 FAILED_ACCESS_ACE_FLAG);
    }
    else
    {
        InvalidFlags = Flags & ~VALID_INHERIT_FLAGS;
    }

    /* If flags are invalid, bail out */
    if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER;

    /* If ACL is invalid, bail out */
    if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL;

    /* If there's no free ACE, bail out */
    if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL;

    /* Calculate the size of the ACE and bail out if it's too small */
    AceSize = RtlLengthSid(Sid) + sizeof(ACE);
    if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize))
    {
        return STATUS_ALLOTTED_SPACE_EXCEEDED;
    }

    /* Initialize the header and common fields */
    Ace->Header.AceFlags = (BYTE)Flags;
    Ace->Header.AceType = Type;
    Ace->Header.AceSize = (WORD)AceSize;
    Ace->Mask = AccessMask;

    /* Copy the SID */
    RtlCopySid(RtlLengthSid(Sid), &Ace->SidStart, Sid);

    /* Fill out the ACL header and return */
    Acl->AceCount++;
    Acl->AclRevision = (BYTE)Revision;
    return STATUS_SUCCESS;
}
Пример #5
0
BOOLEAN
RtlAccessCheckEx(
    IN PSECURITY_DESCRIPTOR_ABSOLUTE SecurityDescriptor,
    IN PACCESS_TOKEN AccessToken,
    IN ACCESS_MASK DesiredAccess,
    IN ACCESS_MASK PreviouslyGrantedAccess,
    IN PGENERIC_MAPPING GenericMapping,
    OUT PACCESS_MASK RemainingDesiredAccess,
    OUT PACCESS_MASK GrantedAccess,
    OUT PNTSTATUS AccessStatus
    )
{
    NTSTATUS status = STATUS_ACCESS_DENIED;
    BOOLEAN isLocked = FALSE;
    ACCESS_MASK grantedAccess = PreviouslyGrantedAccess;
    ACCESS_MASK deniedAccess = 0;
    ACCESS_MASK desiredAccess = DesiredAccess;
    BOOLEAN wantMaxAllowed = FALSE;
    USHORT aclSizeUsed = 0;
    USHORT aceOffset = 0;
    PACE_HEADER aceHeader = NULL;
    union {
        SID Sid;
        BYTE Buffer[SID_MAX_SIZE];
    } sidBuffer;
    ULONG ulSidSize = sizeof(sidBuffer);

    if (!SecurityDescriptor || !AccessToken || !GenericMapping)
    {
        status = STATUS_INVALID_PARAMETER;
        GOTO_CLEANUP();
    }

    if (!LW_IS_VALID_FLAGS(DesiredAccess, VALID_DESIRED_ACCESS_MASK))
    {
        status = STATUS_INVALID_PARAMETER;
        GOTO_CLEANUP();
    }

    if (!LW_IS_VALID_FLAGS(PreviouslyGrantedAccess, VALID_GRANTED_ACCESS_MASK))
    {
        status = STATUS_INVALID_PARAMETER;
        GOTO_CLEANUP();
    }

    if ((SecurityDescriptor->Owner == NULL) || 
        (SecurityDescriptor->Group == NULL))
    {
        status = STATUS_INVALID_SECURITY_DESCR;
        GOTO_CLEANUP();
    }

    wantMaxAllowed = IsSetFlag(desiredAccess, MAXIMUM_ALLOWED);
    ClearFlag(desiredAccess, MAXIMUM_ALLOWED);

    RtlMapGenericMask(&desiredAccess, GenericMapping);

    //
    // NT AUTHORITY\SYSTEM is always allowed an access
    //
    status = RtlCreateWellKnownSid(WinLocalSystemSid,
                                   NULL,
                                   &sidBuffer.Sid,
                                   &ulSidSize);
    GOTO_CLEANUP_ON_STATUS(status);

    SHARED_LOCK_RWLOCK(&AccessToken->RwLock, isLocked);

    if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid))
    {
        if (wantMaxAllowed)
        {
            SetFlag(desiredAccess, STANDARD_RIGHTS_ALL);
            SetFlag(desiredAccess, GENERIC_ALL);
            RtlMapGenericMask(&desiredAccess, GenericMapping);
        }
        SetFlag(grantedAccess, desiredAccess);
        desiredAccess = 0;

        status = STATUS_SUCCESS;
        GOTO_CLEANUP();
    }

    if (wantMaxAllowed || IsSetFlag(desiredAccess, ACCESS_SYSTEM_SECURITY))
    {
        // TODO-Handle ACCESS_SYSTEM_SECURITY by checking SE_SECURITY_NAME
        // privilege.  For now, requesting ACCESS_SYSTEM_SECURITY is not
        // allowed.

        ulSidSize = sizeof(sidBuffer);
        status = RtlCreateWellKnownSid(
                     WinBuiltinAdministratorsSid,
                     NULL,
                     &sidBuffer.Sid,
                     &ulSidSize);
        GOTO_CLEANUP_ON_STATUS(status);

        if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid))
        {
            SetFlag(grantedAccess, ACCESS_SYSTEM_SECURITY);
            ClearFlag(desiredAccess, ACCESS_SYSTEM_SECURITY);
        }
        else if (IsSetFlag(desiredAccess, ACCESS_SYSTEM_SECURITY))
        {
            status = STATUS_PRIVILEGE_NOT_HELD;
            GOTO_CLEANUP();
        }
    }

    if (wantMaxAllowed || IsSetFlag(desiredAccess, WRITE_OWNER))
    {
        // TODO-Allow WRITE_OWNER if have SE_TAKE_OWNERSHIP_NAME regardless
        // of DACL.

        //
        // BUILTIN\Administrators are always allowed WRITE_OWNER
        //

        ulSidSize = sizeof(sidBuffer);
        status = RtlCreateWellKnownSid(
                     WinBuiltinAdministratorsSid,
                     NULL,
                     &sidBuffer.Sid,
                     &ulSidSize);
        GOTO_CLEANUP_ON_STATUS(status);

        if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid))
        {
            SetFlag(grantedAccess, WRITE_OWNER);
            ClearFlag(desiredAccess, WRITE_OWNER);
        }
    }

    //
    // Owner can always read the SD and write the DACL.
    //

    if (wantMaxAllowed || IsSetFlag(desiredAccess, READ_CONTROL | WRITE_DAC))
    {
        if (RtlIsSidMemberOfToken(AccessToken, SecurityDescriptor->Owner))
        {
            if (wantMaxAllowed)
            {
                desiredAccess |= (READ_CONTROL | WRITE_DAC);
            }
                
            SetFlag(grantedAccess, (READ_CONTROL | WRITE_DAC) & desiredAccess);
            ClearFlag(desiredAccess, grantedAccess);
        }
    }

    // TODO-MAXIMUM_ALLOWED wrt privileges and WRITE_OWNER and
    // ACCESS_SYSTEM_SECURITY above.

    if (!SecurityDescriptor->Dacl)
    {
        // TODO-Interplay with special bits above?
        if (wantMaxAllowed)
        {
            SetFlag(desiredAccess, STANDARD_RIGHTS_ALL);
            SetFlag(desiredAccess, GENERIC_ALL);
            RtlMapGenericMask(&desiredAccess, GenericMapping);
        }
        SetFlag(grantedAccess, desiredAccess);
        desiredAccess = 0;

        status = STATUS_SUCCESS;
        GOTO_CLEANUP();
    }

    if (!RtlValidAcl(SecurityDescriptor->Dacl, &aclSizeUsed))
    {
        status = STATUS_INVALID_ACL;
        GOTO_CLEANUP();
    }

    while (wantMaxAllowed || desiredAccess)
    {
        status = RtlIterateAce(SecurityDescriptor->Dacl,
                               aclSizeUsed,
                               &aceOffset,
                               &aceHeader);
        if (STATUS_NO_MORE_ENTRIES == status)
        {
            break;
        }
        GOTO_CLEANUP_ON_STATUS(status);

        // Check ACE
        switch (aceHeader->AceType)
        {
            case ACCESS_ALLOWED_ACE_TYPE:
            {
                PACCESS_ALLOWED_ACE ace = (PACCESS_ALLOWED_ACE) aceHeader;
                ACCESS_MASK mask = ace->Mask;

                RtlMapGenericMask(&mask, GenericMapping);

                if (wantMaxAllowed || IsSetFlag(desiredAccess, mask))
                {
                    // SID in token => add bits to granted bits
                    PSID sid = RtlpGetSidAccessAllowedAce(ace);

                    if (RtlIsSidMemberOfToken(AccessToken, sid))
                    {
                        if (wantMaxAllowed)
                        {
                            SetFlag(grantedAccess, mask & ~deniedAccess);
                        }
                        else
                        {
                            SetFlag(grantedAccess, mask & desiredAccess);
                        }

                        ClearFlag(desiredAccess, grantedAccess);
                    }
                }
                break;
            }
            case ACCESS_DENIED_ACE_TYPE:
            {
                // Allowed and deny ACEs are isomorphic.
                PACCESS_ALLOWED_ACE ace = (PACCESS_ALLOWED_ACE) aceHeader;
                ACCESS_MASK mask = ace->Mask;

                RtlMapGenericMask(&mask, GenericMapping);

                if (wantMaxAllowed || IsSetFlag(desiredAccess, mask))
                {
                    // SID in token => exit with STATUS_ACCESS_DENIED
                    PSID sid = RtlpGetSidAccessAllowedAce(ace);

                    if (RtlIsSidMemberOfToken(AccessToken, sid))
                    {
                        if (wantMaxAllowed)
                        {
                            SetFlag(deniedAccess, mask);
                        }
                        else
                        {
                            status = STATUS_ACCESS_DENIED;
                            GOTO_CLEANUP();
                        }

                        ClearFlag(desiredAccess, deniedAccess);
                    }
                }
                break;
            }
            default:
                // ignore
                break;
        }
    }

    status = desiredAccess ? STATUS_ACCESS_DENIED : STATUS_SUCCESS;

cleanup:
    UNLOCK_RWLOCK(&AccessToken->RwLock, isLocked);

    if (NT_SUCCESS(status) &&
        !LW_IS_VALID_FLAGS(grantedAccess, VALID_GRANTED_ACCESS_MASK))
    {
        status = STATUS_ASSERTION_FAILURE;
    }
    if (!NT_SUCCESS(status))
    {
        grantedAccess = PreviouslyGrantedAccess;
    }

    if (RemainingDesiredAccess)
    {
        *RemainingDesiredAccess = desiredAccess;
    }

    *GrantedAccess = grantedAccess;
    *AccessStatus = status;

    return NT_SUCCESS(status) ? TRUE : FALSE;
}
Пример #6
0
NTSTATUS
RtlCreateAccessToken(
    OUT PACCESS_TOKEN* AccessToken,
    IN PTOKEN_USER User,
    IN PTOKEN_GROUPS Groups,
    IN PTOKEN_PRIVILEGES Privileges,
    IN PTOKEN_OWNER Owner,
    IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
    IN PTOKEN_DEFAULT_DACL DefaultDacl,
    IN OPTIONAL PTOKEN_UNIX Unix
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    int unixError = 0;
    ULONG requiredSize = 0;
    PACCESS_TOKEN token = NULL;
    ULONG i = 0;
    ULONG size = 0;
    PVOID location = NULL;

    if (!User || !User->User.Sid ||
        !Groups ||
        !Owner ||
        !PrimaryGroup ||
        !DefaultDacl)
    {
        status = STATUS_INVALID_PARAMETER;
        GOTO_CLEANUP();
    }

    if (!RtlValidSid(User->User.Sid) ||
        (Owner->Owner && !RtlValidSid(Owner->Owner)) ||
        (PrimaryGroup->PrimaryGroup && !RtlValidSid(PrimaryGroup->PrimaryGroup)))
    {
        status = STATUS_INVALID_SID;
        GOTO_CLEANUP();
    }

    // No user attributes currently exist.
    if (User->User.Attributes != 0)
    {
        status = STATUS_INVALID_PARAMETER;
        GOTO_CLEANUP();
    }

    for (i = 0; i < Groups->GroupCount; i++)
    {
        // TODO-Perhaps validate Group attributes
        if (!Groups->Groups[i].Sid)
        {
            status = STATUS_INVALID_PARAMETER;
            GOTO_CLEANUP();
        }
        if (!RtlValidSid(Groups->Groups[i].Sid))
        {
            status = STATUS_INVALID_SID;
            GOTO_CLEANUP();
        }
    }

    if (DefaultDacl->DefaultDacl &&
        !RtlValidAcl(DefaultDacl->DefaultDacl, NULL))
    {
        status = STATUS_INVALID_ACL;
        GOTO_CLEANUP();
    }

    // Compute size required

    requiredSize = sizeof(*token);

    size = RtlLengthSid(User->User.Sid);
    status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
    GOTO_CLEANUP_ON_STATUS(status);

    if (Owner->Owner)
    {
        size = RtlLengthSid(Owner->Owner);
        status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
        GOTO_CLEANUP_ON_STATUS(status);
    }

    if (PrimaryGroup->PrimaryGroup)
    {
        size = RtlLengthSid(PrimaryGroup->PrimaryGroup);
        status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
        GOTO_CLEANUP_ON_STATUS(status);
    }

    if (DefaultDacl->DefaultDacl)
    {
        status = RtlSafeAddULONG(&requiredSize, requiredSize,
                                 DefaultDacl->DefaultDacl->AclSize);
        GOTO_CLEANUP_ON_STATUS(status);
    }

    status = RtlSafeMultiplyULONG(&size, sizeof(Groups->Groups[0]), Groups->GroupCount);
    GOTO_CLEANUP_ON_STATUS(status);

    status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
    GOTO_CLEANUP_ON_STATUS(status);

    for (i = 0; i < Groups->GroupCount; i++)
    {
        size = RtlLengthSid(Groups->Groups[i].Sid);

        status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
        GOTO_CLEANUP_ON_STATUS(status);
    }

    status = RtlSafeMultiplyULONG(&size,
                                  sizeof(Privileges->Privileges[0]),
                                  Privileges->PrivilegeCount);
    GOTO_CLEANUP_ON_STATUS(status);

    status = RtlSafeAddULONG(&requiredSize, requiredSize, size);
    GOTO_CLEANUP_ON_STATUS(status);

    status = RTL_ALLOCATE(&token, ACCESS_TOKEN, requiredSize);
    GOTO_CLEANUP_ON_STATUS(status);

    location = LW_PTR_ADD(token, sizeof(*token));

    // Initialize

    token->ReferenceCount = 1;
    token->Flags = 0;
    unixError = pthread_rwlock_init(&token->RwLock, NULL);
    if (unixError)
    {
        LW_RTL_LOG_ERROR("Failed to init rwlock in access token "
                         "(error = %d).", unixError);
        status = LwErrnoToNtStatus(unixError);
        GOTO_CLEANUP();
    }
    token->pRwLock = &token->RwLock;

    token->User.Attributes = User->User.Attributes;
    token->User.Sid = (PSID) location;
    location = RtlpAppendData(location,
                              User->User.Sid,
                              RtlLengthSid(User->User.Sid));

    token->GroupCount = Groups->GroupCount;
    token->Groups = (PSID_AND_ATTRIBUTES) location;
    location = LwRtlOffsetToPointer(location, sizeof(Groups->Groups[0]) * Groups->GroupCount);
    for (i = 0; i < Groups->GroupCount; i++)
    {
        token->Groups[i].Attributes = Groups->Groups[i].Attributes;
        token->Groups[i].Sid = (PSID) location;
        location = RtlpAppendData(location,
                                  Groups->Groups[i].Sid,
                                  RtlLengthSid(Groups->Groups[i].Sid));
    }

    token->PrivilegeCount = Privileges->PrivilegeCount;
    token->Privileges = (PLUID_AND_ATTRIBUTES) location;
    location = LwRtlOffsetToPointer(
                location,
                sizeof(Privileges->Privileges[0]) * Privileges->PrivilegeCount);
    memcpy(token->Privileges,
           Privileges->Privileges,
           sizeof(token->Privileges[0]) * token->PrivilegeCount);

    if (Owner->Owner)
    {
        token->Owner = (PSID) location;
        location = RtlpAppendData(location,
                                  Owner->Owner,
                                  RtlLengthSid(Owner->Owner));
    }

    if (PrimaryGroup->PrimaryGroup)
    {
        token->PrimaryGroup = (PSID) location;
        location = RtlpAppendData(location,
                                  PrimaryGroup->PrimaryGroup,
                                  RtlLengthSid(PrimaryGroup->PrimaryGroup));
    }

    if (DefaultDacl->DefaultDacl)
    {
        token->DefaultDacl = (PACL) location;
        location = RtlpAppendData(location,
                                  DefaultDacl->DefaultDacl,
                                  DefaultDacl->DefaultDacl->AclSize);
    }

    if (Unix)
    {
        SetFlag(token->Flags, ACCESS_TOKEN_FLAG_UNIX_PRESENT);
        token->Uid = Unix->Uid;
        token->Gid = Unix->Gid;
        token->Umask = Unix->Umask;
    }

    if (location != LW_PTR_ADD(token, requiredSize))
    {
        status = STATUS_ASSERTION_FAILURE;
        GOTO_CLEANUP();
    }

    status = STATUS_SUCCESS;

cleanup:
    if (!NT_SUCCESS(status))
    {
        RtlReleaseAccessToken(&token);
    }

    *AccessToken = token;

    return status;
}