diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 9c492659e75..bc99d1a759c 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -535,6 +535,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, LPCVOID data, ULONG length ) { + NTSTATUS status; switch(class) { case ThreadZeroTlsCell: @@ -577,8 +578,16 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, { const HANDLE *phToken = data; if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER; - FIXME("Set ThreadImpersonationToken handle to %p\n", *phToken ); - return STATUS_SUCCESS; + TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken ); + SERVER_START_REQ( set_thread_info ) + { + req->handle = handle; + req->token = *phToken; + req->mask = SET_THREAD_INFO_TOKEN; + status = wine_server_call( req ); + } + SERVER_END_REQ; + return status; } case ThreadBasicInformation: case ThreadTimes: diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e86c74fc739..099e988906f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -414,6 +414,7 @@ struct set_thread_info_request int mask; int priority; int affinity; + obj_handle_t token; }; struct set_thread_info_reply { @@ -421,6 +422,7 @@ struct set_thread_info_reply }; #define SET_THREAD_INFO_PRIORITY 0x01 #define SET_THREAD_INFO_AFFINITY 0x02 +#define SET_THREAD_INFO_TOKEN 0x04 @@ -4186,6 +4188,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 178 +#define SERVER_PROTOCOL_VERSION 179 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 7392ce96239..2f6556ea680 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -360,9 +360,11 @@ struct security_descriptor int mask; /* setting mask (see below) */ int priority; /* priority class */ int affinity; /* affinity mask */ + obj_handle_t token; /* impersonation token */ @END #define SET_THREAD_INFO_PRIORITY 0x01 #define SET_THREAD_INFO_AFFINITY 0x02 +#define SET_THREAD_INFO_TOKEN 0x04 /* Retrieve information about a module */ diff --git a/server/security.h b/server/security.h index 0be5f20dd0c..14817660363 100644 --- a/server/security.h +++ b/server/security.h @@ -43,6 +43,7 @@ extern struct token *token_create_admin(void); extern int token_check_privileges( struct token *token, int all_required, const LUID_AND_ATTRIBUTES *reqprivs, unsigned int count, LUID_AND_ATTRIBUTES *usedprivs); +extern void security_set_thread_token( struct thread *thread, obj_handle_t handle ); static inline int thread_single_check_privilege( struct thread *thread, const LUID *priv) { diff --git a/server/thread.c b/server/thread.c index 5f4fdeef1c4..c11c18ab54e 100644 --- a/server/thread.c +++ b/server/thread.c @@ -45,6 +45,7 @@ #include "thread.h" #include "request.h" #include "user.h" +#include "security.h" /* thread queues */ @@ -314,6 +315,8 @@ static void set_thread_info( struct thread *thread, if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER ); else thread->affinity = req->affinity; } + if (req->mask & SET_THREAD_INFO_TOKEN) + security_set_thread_token( thread, req->token ); } /* stop a thread (at the Unix level) */ diff --git a/server/token.c b/server/token.c index f1fba3b27ca..c9ec0cebfdf 100644 --- a/server/token.c +++ b/server/token.c @@ -140,6 +140,29 @@ static inline int security_equal_sid( const SID *sid1, const SID *sid2 ) !memcmp( sid1, sid2, FIELD_OFFSET(SID, SubAuthority[sid1->SubAuthorityCount]) )); } +void security_set_thread_token( struct thread *thread, obj_handle_t handle ) +{ + if (!handle) + { + if (thread->token) + release_object( thread->token ); + thread->token = NULL; + } + else + { + struct token *token = (struct token *)get_handle_obj( current->process, + handle, + TOKEN_IMPERSONATE, + &token_ops ); + if (token) + { + if (thread->token) + release_object( thread->token ); + thread->token = token; + } + } +} + static const ACE_HEADER *ace_next( const ACE_HEADER *ace ) { return (const ACE_HEADER *)((const char *)ace + ace->AceSize); @@ -964,8 +987,13 @@ DECL_HANDLER(access_check) memset(&priv, 0, sizeof(priv)); - /* FIXME: check token is an impersonation token, if not return - * STATUS_NO_IMPERSONATION_TOKEN */ + /* only impersonation tokens may be used with this function */ + if (token->primary) + { + set_error( STATUS_NO_IMPERSONATION_TOKEN ); + release_object( token ); + return; + } mapping.GenericRead = req->mapping_read; mapping.GenericWrite = req->mapping_write; diff --git a/server/trace.c b/server/trace.c index d4a1eb2926c..1dcfa0633bb 100644 --- a/server/trace.c +++ b/server/trace.c @@ -741,7 +741,8 @@ static void dump_set_thread_info_request( const struct set_thread_info_request * fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " mask=%d,", req->mask ); fprintf( stderr, " priority=%d,", req->priority ); - fprintf( stderr, " affinity=%d", req->affinity ); + fprintf( stderr, " affinity=%d,", req->affinity ); + fprintf( stderr, " token=%p", req->token ); } static void dump_get_dll_info_request( const struct get_dll_info_request *req )