From: Zebediah Figura zfigura@codeweavers.com
--- dlls/ntdll/tests/info.c | 74 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/process.c | 17 +++++++++ dlls/wow64/process.c | 13 +++++++ dlls/wow64/struct32.h | 6 ++++ include/ddk/ntddk.h | 6 ++++ server/process.c | 16 +++++++++ server/protocol.def | 7 ++++ 7 files changed, 139 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 70d566df3c6..5028dd11e99 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -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); } diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index bf24161fedb..43dca59eb3a 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -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,22 @@ 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_token ) + { + req->process = wine_server_obj_handle( handle ); + req->token = wine_server_obj_handle( token->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; diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index 817926d0f13..8b543d2a859 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -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)) { diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 482f1297b28..2c4cf4f9e3c 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -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 */ diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h index 471c27c27ba..c705958e147 100644 --- a/include/ddk/ntddk.h +++ b/include/ddk/ntddk.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, diff --git a/server/process.c b/server/process.c index c9ab161e3fb..1a49821bef1 100644 --- a/server/process.c +++ b/server/process.c @@ -1630,6 +1630,22 @@ DECL_HANDLER(set_process_info) } }
+/* set the process's primary token */ +DECL_HANDLER(set_process_token) +{ + struct process *process; + struct token *token; + + if (!(process = get_process_from_handle( req->process, PROCESS_SET_INFORMATION ))) return; + + if ((token = get_token_obj( current->process, req->token, TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY ))) + { + release_object( process->token ); + process->token = token; + } + release_object( process ); +} + /* read data from a process address space */ DECL_HANDLER(read_process_memory) { diff --git a/server/protocol.def b/server/protocol.def index fa78e0487f8..4b911260bbd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3607,6 +3607,13 @@ struct handle_info @END
+/* Set the process's primary token */ +@REQ(set_process_token) + obj_handle_t process; /* handle to the process */ + obj_handle_t token; /* handle to the token */ +@END + + /* Create I/O completion port */ @REQ(create_completion) unsigned int access; /* desired access to a port */