509 lines
16 KiB
C
509 lines
16 KiB
C
/*
|
|
* WoW64 security functions
|
|
*
|
|
* Copyright 2021 Alexandre Julliard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "ntstatus.h"
|
|
#define WIN32_NO_STATUS
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winnt.h"
|
|
#include "winternl.h"
|
|
#include "wow64_private.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wow);
|
|
|
|
|
|
static TOKEN_GROUPS *token_groups_32to64( const TOKEN_GROUPS32 *groups32 )
|
|
{
|
|
TOKEN_GROUPS *groups;
|
|
ULONG i;
|
|
|
|
if (!groups32) return NULL;
|
|
groups = Wow64AllocateTemp( offsetof( TOKEN_GROUPS, Groups[groups32->GroupCount] ));
|
|
groups->GroupCount = groups32->GroupCount;
|
|
for (i = 0; i < groups->GroupCount; i++)
|
|
{
|
|
groups->Groups[i].Sid = ULongToPtr( groups32->Groups[i].Sid );
|
|
groups->Groups[i].Attributes = groups32->Groups[i].Attributes;
|
|
}
|
|
return groups;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAccessCheck
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAccessCheck( UINT *args )
|
|
{
|
|
SECURITY_DESCRIPTOR *sd32 = get_ptr( &args );
|
|
HANDLE handle = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
GENERIC_MAPPING *mapping = get_ptr( &args );
|
|
PRIVILEGE_SET *privs = get_ptr( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
ACCESS_MASK *access_granted = get_ptr( &args );
|
|
NTSTATUS *access_status = get_ptr( &args );
|
|
|
|
SECURITY_DESCRIPTOR sd;
|
|
|
|
return NtAccessCheck( secdesc_32to64( &sd, sd32 ), handle, access, mapping,
|
|
privs, retlen, access_granted, access_status );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAccessCheckAndAuditAlarm
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAccessCheckAndAuditAlarm( UINT *args )
|
|
{
|
|
UNICODE_STRING32 *subsystem32 = get_ptr( &args );
|
|
HANDLE handle = get_handle( &args );
|
|
UNICODE_STRING32 *typename32 = get_ptr( &args );
|
|
UNICODE_STRING32 *objname32 = get_ptr( &args );
|
|
SECURITY_DESCRIPTOR *sd32 = get_ptr( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
GENERIC_MAPPING *mapping = get_ptr( &args );
|
|
BOOLEAN creation = get_ulong( &args );
|
|
ACCESS_MASK *access_granted = get_ptr( &args );
|
|
BOOLEAN *access_status = get_ptr( &args );
|
|
BOOLEAN *onclose = get_ptr( &args );
|
|
|
|
UNICODE_STRING subsystem, typename, objname;
|
|
SECURITY_DESCRIPTOR sd;
|
|
|
|
return NtAccessCheckAndAuditAlarm( unicode_str_32to64( &subsystem, subsystem32 ), handle,
|
|
unicode_str_32to64( &typename, typename32 ),
|
|
unicode_str_32to64( &objname, objname32 ),
|
|
secdesc_32to64( &sd, sd32 ), access, mapping, creation,
|
|
access_granted, access_status, onclose );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAdjustGroupsToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAdjustGroupsToken( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
BOOLEAN reset = get_ulong( &args );
|
|
TOKEN_GROUPS32 *groups = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
TOKEN_GROUPS32 *prev = get_ptr( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
|
|
FIXME( "%p %d %p %u %p %p\n", handle, reset, groups, len, prev, retlen );
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAdjustPrivilegesToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAdjustPrivilegesToken( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
BOOLEAN disable = get_ulong( &args );
|
|
TOKEN_PRIVILEGES *privs = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
TOKEN_PRIVILEGES *prev = get_ptr( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
|
|
return NtAdjustPrivilegesToken( handle, disable, privs, len, prev, retlen );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtCreateLowBoxToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtCreateLowBoxToken( UINT *args )
|
|
{
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
HANDLE token = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args );
|
|
SID *sid = get_ptr( &args );
|
|
ULONG count = get_ulong( &args );
|
|
SID_AND_ATTRIBUTES32 *capabilities32 = get_ptr( &args );
|
|
ULONG handle_count = get_ulong( &args );
|
|
ULONG *handles32 = get_ptr( &args );
|
|
|
|
FIXME( "%p %p %x %p %p %u %p %u %p: stub\n",
|
|
handle_ptr, token, access, attr32, sid, count, capabilities32, handle_count, handles32 );
|
|
|
|
*handle_ptr = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtDuplicateToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtDuplicateToken( UINT *args )
|
|
{
|
|
HANDLE token = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args );
|
|
SECURITY_IMPERSONATION_LEVEL level = get_ulong( &args );
|
|
TOKEN_TYPE type = get_ulong( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
struct object_attr64 attr;
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtDuplicateToken( token, access, objattr_32to64( &attr, attr32 ), level, type, &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtFilterToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtFilterToken( UINT *args )
|
|
{
|
|
HANDLE token = get_handle( &args );
|
|
ULONG flags = get_ulong( &args );
|
|
TOKEN_GROUPS32 *disable_sids32 = get_ptr( &args );
|
|
TOKEN_PRIVILEGES *privs = get_ptr( &args );
|
|
TOKEN_GROUPS32 *restrict_sids32 = get_ptr( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtFilterToken( token, flags, token_groups_32to64( disable_sids32 ), privs,
|
|
token_groups_32to64( restrict_sids32 ), &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtImpersonateAnonymousToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtImpersonateAnonymousToken( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
|
|
return NtImpersonateAnonymousToken( handle );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtOpenProcessToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtOpenProcessToken( UINT *args )
|
|
{
|
|
HANDLE process = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtOpenProcessToken( process, access, &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtOpenProcessTokenEx
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtOpenProcessTokenEx( UINT *args )
|
|
{
|
|
HANDLE process = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
ULONG attributes = get_ulong( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtOpenProcessTokenEx( process, access, attributes, &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtOpenThreadToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtOpenThreadToken( UINT *args )
|
|
{
|
|
HANDLE thread = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
BOOLEAN self = get_ulong( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtOpenThreadToken( thread, access, self, &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtOpenThreadTokenEx
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtOpenThreadTokenEx( UINT *args )
|
|
{
|
|
HANDLE thread = get_handle( &args );
|
|
ACCESS_MASK access = get_ulong( &args );
|
|
BOOLEAN self = get_ulong( &args );
|
|
ULONG attributes = get_ulong( &args );
|
|
ULONG *handle_ptr = get_ptr( &args );
|
|
|
|
HANDLE handle = 0;
|
|
NTSTATUS status;
|
|
|
|
*handle_ptr = 0;
|
|
status = NtOpenThreadTokenEx( thread, access, self, attributes, &handle );
|
|
put_handle( handle_ptr, handle );
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtPrivilegeCheck
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtPrivilegeCheck( UINT *args )
|
|
{
|
|
HANDLE token = get_handle( &args );
|
|
PRIVILEGE_SET *privs = get_ptr( &args );
|
|
BOOLEAN *res = get_ptr( &args );
|
|
|
|
return NtPrivilegeCheck( token, privs, res );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQueryInformationToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQueryInformationToken( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
TOKEN_INFORMATION_CLASS class = get_ulong( &args );
|
|
void *info = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
|
|
NTSTATUS status;
|
|
ULONG ret_size, sid_len;
|
|
|
|
switch (class)
|
|
{
|
|
case TokenPrivileges: /* TOKEN_PRIVILEGES */
|
|
case TokenImpersonationLevel: /* SECURITY_IMPERSONATION_LEVEL */
|
|
case TokenStatistics: /* TOKEN_STATISTICS */
|
|
case TokenType: /* TOKEN_TYPE */
|
|
case TokenElevationType: /* TOKEN_ELEVATION_TYPE */
|
|
case TokenElevation: /* TOKEN_ELEVATION */
|
|
case TokenSessionId: /* ULONG */
|
|
case TokenVirtualizationEnabled: /* ULONG */
|
|
case TokenIsAppContainer: /* ULONG */
|
|
/* nothing to map */
|
|
return NtQueryInformationToken( handle, class, info, len, retlen );
|
|
|
|
case TokenUser: /* TOKEN_USER + SID */
|
|
case TokenIntegrityLevel: /* TOKEN_MANDATORY_LABEL + SID */
|
|
{
|
|
ULONG_PTR buffer[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(ULONG_PTR)];
|
|
TOKEN_USER *user = (TOKEN_USER *)buffer;
|
|
TOKEN_USER32 *user32 = info;
|
|
SID *sid;
|
|
|
|
status = NtQueryInformationToken( handle, class, &buffer, sizeof(buffer), &ret_size );
|
|
if (status) return status;
|
|
sid = user->User.Sid;
|
|
sid_len = offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
|
|
if (len >= sizeof(*user32) + sid_len)
|
|
{
|
|
user32->User.Sid = PtrToUlong( user32 + 1 );
|
|
user32->User.Attributes = user->User.Attributes;
|
|
memcpy( user32 + 1, sid, sid_len );
|
|
}
|
|
else status = STATUS_BUFFER_TOO_SMALL;
|
|
if (retlen) *retlen = sizeof(*user32) + sid_len;
|
|
return status;
|
|
}
|
|
|
|
case TokenOwner: /* TOKEN_OWNER + SID */
|
|
case TokenPrimaryGroup: /* TOKEN_PRIMARY_GROUP + SID */
|
|
case TokenAppContainerSid: /* TOKEN_APPCONTAINER_INFORMATION + SID */
|
|
{
|
|
ULONG_PTR buffer[(sizeof(TOKEN_OWNER) + SECURITY_MAX_SID_SIZE) / sizeof(ULONG_PTR)];
|
|
TOKEN_OWNER *owner = (TOKEN_OWNER *)buffer;
|
|
TOKEN_OWNER32 *owner32 = info;
|
|
SID *sid;
|
|
|
|
status = NtQueryInformationToken( handle, class, &buffer, sizeof(buffer), &ret_size );
|
|
if (status) return status;
|
|
sid = owner->Owner;
|
|
sid_len = offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
|
|
if (len >= sizeof(*owner32) + sid_len)
|
|
{
|
|
owner32->Owner = PtrToUlong( owner32 + 1 );
|
|
memcpy( owner32 + 1, sid, sid_len );
|
|
}
|
|
else status = STATUS_BUFFER_TOO_SMALL;
|
|
if (retlen) *retlen = sizeof(*owner32) + sid_len;
|
|
return status;
|
|
}
|
|
|
|
case TokenGroups: /* TOKEN_GROUPS */
|
|
case TokenLogonSid: /* TOKEN_GROUPS */
|
|
{
|
|
TOKEN_GROUPS32 *groups32 = info;
|
|
TOKEN_GROUPS *groups;
|
|
ULONG i, group_len, group32_len;
|
|
|
|
status = NtQueryInformationToken( handle, class, NULL, 0, &ret_size );
|
|
if (status != STATUS_BUFFER_TOO_SMALL) return status;
|
|
groups = Wow64AllocateTemp( ret_size );
|
|
status = NtQueryInformationToken( handle, class, groups, ret_size, &ret_size );
|
|
if (status) return status;
|
|
group_len = offsetof( TOKEN_GROUPS, Groups[groups->GroupCount] );
|
|
group32_len = offsetof( TOKEN_GROUPS32, Groups[groups->GroupCount] );
|
|
sid_len = ret_size - group_len;
|
|
ret_size = group32_len + sid_len;
|
|
if (len >= ret_size)
|
|
{
|
|
SID *sid = (SID *)((char *)groups + group_len);
|
|
SID *sid32 = (SID *)((char *)groups32 + group32_len);
|
|
|
|
memcpy( sid32, sid, sid_len );
|
|
groups32->GroupCount = groups->GroupCount;
|
|
for (i = 0; i < groups->GroupCount; i++)
|
|
{
|
|
groups32->Groups[i].Sid = PtrToUlong(sid32) + ((char *)groups->Groups[i].Sid - (char *)sid);
|
|
groups32->Groups[i].Attributes = groups->Groups[i].Attributes;
|
|
}
|
|
}
|
|
else status = STATUS_BUFFER_TOO_SMALL;
|
|
if (retlen) *retlen = ret_size;
|
|
return status;
|
|
}
|
|
|
|
case TokenDefaultDacl: /* TOKEN_DEFAULT_DACL + ACL */
|
|
{
|
|
ULONG size = len + sizeof(TOKEN_DEFAULT_DACL) - sizeof(TOKEN_DEFAULT_DACL32);
|
|
TOKEN_DEFAULT_DACL32 *dacl32 = info;
|
|
TOKEN_DEFAULT_DACL *dacl = Wow64AllocateTemp( size );
|
|
|
|
status = NtQueryInformationToken( handle, class, dacl, size, &ret_size );
|
|
if (!status)
|
|
{
|
|
dacl32->DefaultDacl = dacl->DefaultDacl ? PtrToUlong( dacl32 + 1 ) : 0;
|
|
memcpy( dacl32 + 1, dacl->DefaultDacl, ret_size - sizeof(*dacl) );
|
|
}
|
|
if (retlen) *retlen = ret_size + sizeof(*dacl32) - sizeof(*dacl);
|
|
return status;
|
|
}
|
|
|
|
case TokenLinkedToken: /* TOKEN_LINKED_TOKEN */
|
|
{
|
|
TOKEN_LINKED_TOKEN link;
|
|
|
|
status = NtQueryInformationToken( handle, class, &link, sizeof(link), &ret_size );
|
|
if (!status) *(ULONG *)info = HandleToLong( link.LinkedToken );
|
|
if (retlen) *retlen = sizeof(ULONG);
|
|
return status;
|
|
}
|
|
|
|
default:
|
|
FIXME( "unsupported class %u\n", class );
|
|
return STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQuerySecurityObject
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQuerySecurityObject( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
SECURITY_INFORMATION info = get_ulong( &args );
|
|
SECURITY_DESCRIPTOR *sd = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
|
|
/* returned descriptor is always SE_SELF_RELATIVE, no mapping needed */
|
|
return NtQuerySecurityObject( handle, info, sd, len, retlen );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtSetInformationToken
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtSetInformationToken( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
TOKEN_INFORMATION_CLASS class = get_ulong( &args );
|
|
void *ptr = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
|
|
switch (class)
|
|
{
|
|
case TokenSessionId: /* ULONG */
|
|
return NtSetInformationToken( handle, class, ptr, len );
|
|
|
|
case TokenDefaultDacl: /* TOKEN_DEFAULT_DACL */
|
|
if (len >= sizeof(TOKEN_DEFAULT_DACL32))
|
|
{
|
|
TOKEN_DEFAULT_DACL32 *dacl32 = ptr;
|
|
TOKEN_DEFAULT_DACL dacl = { ULongToPtr( dacl32->DefaultDacl ) };
|
|
|
|
return NtSetInformationToken( handle, class, &dacl, sizeof(dacl) );
|
|
}
|
|
else return STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
default:
|
|
FIXME( "unsupported class %u\n", class );
|
|
return STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtSetSecurityObject
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtSetSecurityObject( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
SECURITY_INFORMATION info = get_ulong( &args );
|
|
SECURITY_DESCRIPTOR *sd32 = get_ptr( &args );
|
|
|
|
SECURITY_DESCRIPTOR sd;
|
|
|
|
return NtSetSecurityObject( handle, info, secdesc_32to64( &sd, sd32 ));
|
|
}
|