/* * 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 )); }