ntdll: Implement NtSetInformationProcess(ProcessAccessToken).
This commit is contained in:
parent
3103adb6a6
commit
95a91bd816
10 changed files with 136 additions and 2 deletions
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "ntdll_test.h"
|
||||
#include <winnls.h>
|
||||
#include <ddk/ntddk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
|
||||
|
@ -3758,6 +3759,78 @@ static void test_system_debug_control(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_process_token(int argc, char **argv)
|
||||
{
|
||||
STARTUPINFOA si = {.cb = sizeof(si)};
|
||||
PROCESS_ACCESS_TOKEN token_info = {0};
|
||||
TOKEN_STATISTICS stats1, stats2;
|
||||
HANDLE token, their_token;
|
||||
PROCESS_INFORMATION pi;
|
||||
char cmdline[MAX_PATH];
|
||||
NTSTATUS status;
|
||||
DWORD size;
|
||||
BOOL ret;
|
||||
|
||||
token_info.Thread = (HANDLE)0xdeadbeef;
|
||||
|
||||
sprintf( cmdline, "%s %s dummy", argv[0], argv[1] );
|
||||
|
||||
ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) - 1 );
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx\n", status );
|
||||
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) );
|
||||
ok( status == STATUS_INVALID_HANDLE, "got %#lx\n", status );
|
||||
|
||||
ret = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | READ_CONTROL | TOKEN_DUPLICATE
|
||||
| TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_DEFAULT, &token );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
|
||||
token_info.Token = token;
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) );
|
||||
todo_wine ok( status == STATUS_TOKEN_ALREADY_IN_USE, "got %#lx\n", status );
|
||||
|
||||
ret = DuplicateTokenEx( token, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenImpersonation, &token_info.Token );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) );
|
||||
todo_wine ok( status == STATUS_BAD_IMPERSONATION_LEVEL, "got %#lx\n", status );
|
||||
CloseHandle( token_info.Token );
|
||||
|
||||
ret = DuplicateTokenEx( token, TOKEN_QUERY, NULL, SecurityAnonymous, TokenPrimary, &token_info.Token );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) );
|
||||
ok( status == STATUS_ACCESS_DENIED, "got %#lx\n", status );
|
||||
CloseHandle( token_info.Token );
|
||||
|
||||
ret = DuplicateTokenEx( token, TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, NULL, SecurityAnonymous, TokenPrimary, &token_info.Token );
|
||||
ok(ret, "got error %lu\n", GetLastError());
|
||||
status = pNtSetInformationProcess( pi.hProcess, ProcessAccessToken, &token_info, sizeof(token_info) );
|
||||
ok( status == STATUS_SUCCESS, "got %#lx\n", status );
|
||||
|
||||
ret = OpenProcessToken( pi.hProcess, TOKEN_QUERY, &their_token );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
|
||||
/* The tokens should be the same. */
|
||||
ret = GetTokenInformation( token_info.Token, TokenStatistics, &stats1, sizeof(stats1), &size );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
ret = GetTokenInformation( their_token, TokenStatistics, &stats2, sizeof(stats2), &size );
|
||||
ok( ret, "got error %lu\n", GetLastError() );
|
||||
ok( !memcmp( &stats1.TokenId, &stats2.TokenId, sizeof(LUID) ), "expected same IDs\n" );
|
||||
|
||||
CloseHandle( token_info.Token );
|
||||
CloseHandle( their_token );
|
||||
|
||||
ResumeThread( pi.hThread );
|
||||
ret = WaitForSingleObject( pi.hProcess, 1000 );
|
||||
ok( !ret, "got %d\n", ret );
|
||||
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
CloseHandle( token );
|
||||
}
|
||||
|
||||
START_TEST(info)
|
||||
{
|
||||
char **argv;
|
||||
|
@ -3834,4 +3907,5 @@ START_TEST(info)
|
|||
test_ThreadEnableAlignmentFaultFixup();
|
||||
test_process_instrumentation_callback();
|
||||
test_system_debug_control();
|
||||
test_process_token(argc, argv);
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "winioctl.h"
|
||||
#include "ddk/ntddk.h"
|
||||
#include "unix_private.h"
|
||||
#include "wine/condrv.h"
|
||||
#include "wine/server.h"
|
||||
|
@ -1600,6 +1601,23 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class,
|
|||
|
||||
switch (class)
|
||||
{
|
||||
case ProcessAccessToken:
|
||||
{
|
||||
const PROCESS_ACCESS_TOKEN *token = info;
|
||||
|
||||
if (size != sizeof(PROCESS_ACCESS_TOKEN)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
SERVER_START_REQ( set_process_info )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
req->token = wine_server_obj_handle( token->Token );
|
||||
req->mask = SET_PROCESS_INFO_TOKEN;
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
break;
|
||||
}
|
||||
|
||||
case ProcessDefaultHardErrorMode:
|
||||
if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
|
||||
process_error_mode = *(UINT *)info;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "winbase.h"
|
||||
#include "winnt.h"
|
||||
#include "winternl.h"
|
||||
#include "ddk/ntddk.h"
|
||||
#include "wow64_private.h"
|
||||
#include "wine/asm.h"
|
||||
#include "wine/exception.h"
|
||||
|
@ -835,6 +836,18 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args )
|
|||
case ProcessLeapSecondInformation: /* PROCESS_LEAP_SECOND_INFO */
|
||||
return NtSetInformationProcess( handle, class, ptr, len );
|
||||
|
||||
case ProcessAccessToken: /* PROCESS_ACCESS_TOKEN */
|
||||
if (len == sizeof(PROCESS_ACCESS_TOKEN32))
|
||||
{
|
||||
PROCESS_ACCESS_TOKEN32 *stack = ptr;
|
||||
PROCESS_ACCESS_TOKEN info;
|
||||
|
||||
info.Thread = ULongToHandle( stack->Thread );
|
||||
info.Token = ULongToHandle( stack->Token );
|
||||
return NtSetInformationProcess( handle, class, &info, sizeof(info) );
|
||||
}
|
||||
else return STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
case ProcessAffinityMask: /* ULONG_PTR */
|
||||
if (len == sizeof(ULONG))
|
||||
{
|
||||
|
|
|
@ -722,4 +722,10 @@ typedef struct DECLSPEC_ALIGN(8)
|
|||
};
|
||||
} MEM_EXTENDED_PARAMETER32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Token;
|
||||
ULONG Thread;
|
||||
} PROCESS_ACCESS_TOKEN32;
|
||||
|
||||
#endif /* __WOW64_STRUCT32_H */
|
||||
|
|
|
@ -146,6 +146,12 @@ typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION
|
|||
LARGE_INTEGER ValidDataLength;
|
||||
} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;
|
||||
|
||||
typedef struct _PROCESS_ACCESS_TOKEN
|
||||
{
|
||||
HANDLE Token;
|
||||
HANDLE Thread;
|
||||
} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;
|
||||
|
||||
typedef enum _RTL_GENERIC_COMPARE_RESULTS
|
||||
{
|
||||
GenericLessThan,
|
||||
|
|
|
@ -1114,6 +1114,8 @@ struct set_process_info_request
|
|||
int mask;
|
||||
int priority;
|
||||
affinity_t affinity;
|
||||
obj_handle_t token;
|
||||
char __pad_36[4];
|
||||
};
|
||||
struct set_process_info_reply
|
||||
{
|
||||
|
@ -1121,6 +1123,7 @@ struct set_process_info_reply
|
|||
};
|
||||
#define SET_PROCESS_INFO_PRIORITY 0x01
|
||||
#define SET_PROCESS_INFO_AFFINITY 0x02
|
||||
#define SET_PROCESS_INFO_TOKEN 0x04
|
||||
|
||||
|
||||
|
||||
|
@ -6502,7 +6505,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 795
|
||||
#define SERVER_PROTOCOL_VERSION 796
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -1626,6 +1626,16 @@ DECL_HANDLER(set_process_info)
|
|||
{
|
||||
if (req->mask & SET_PROCESS_INFO_PRIORITY) process->priority = req->priority;
|
||||
if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity );
|
||||
if (req->mask & SET_PROCESS_INFO_TOKEN)
|
||||
{
|
||||
struct token *token;
|
||||
|
||||
if ((token = get_token_obj( current->process, req->token, TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY )))
|
||||
{
|
||||
release_object( process->token );
|
||||
process->token = token;
|
||||
}
|
||||
}
|
||||
release_object( process );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1047,9 +1047,11 @@ typedef struct
|
|||
int mask; /* setting mask (see below) */
|
||||
int priority; /* priority class */
|
||||
affinity_t affinity; /* affinity mask */
|
||||
obj_handle_t token; /* primary token */
|
||||
@END
|
||||
#define SET_PROCESS_INFO_PRIORITY 0x01
|
||||
#define SET_PROCESS_INFO_AFFINITY 0x02
|
||||
#define SET_PROCESS_INFO_TOKEN 0x04
|
||||
|
||||
|
||||
/* Retrieve information about a thread */
|
||||
|
|
|
@ -848,7 +848,8 @@ C_ASSERT( FIELD_OFFSET(struct set_process_info_request, handle) == 12 );
|
|||
C_ASSERT( FIELD_OFFSET(struct set_process_info_request, mask) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_process_info_request, priority) == 20 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_process_info_request, affinity) == 24 );
|
||||
C_ASSERT( sizeof(struct set_process_info_request) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_process_info_request, token) == 32 );
|
||||
C_ASSERT( sizeof(struct set_process_info_request) == 40 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_request, handle) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_request, access) == 16 );
|
||||
C_ASSERT( sizeof(struct get_thread_info_request) == 24 );
|
||||
|
|
|
@ -1568,6 +1568,7 @@ static void dump_set_process_info_request( const struct set_process_info_request
|
|||
fprintf( stderr, ", mask=%d", req->mask );
|
||||
fprintf( stderr, ", priority=%d", req->priority );
|
||||
dump_uint64( ", affinity=", &req->affinity );
|
||||
fprintf( stderr, ", token=%04x", req->token );
|
||||
}
|
||||
|
||||
static void dump_get_thread_info_request( const struct get_thread_info_request *req )
|
||||
|
|
Loading…
Add table
Reference in a new issue