From ec9244f056b1063be602412a34a12d46f74debb2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 16 Feb 2021 23:31:12 -0600 Subject: [PATCH] ntdll: Implement NtQueryInformationToken(TokenLinkedToken). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/advapi32/tests/security.c | 11 +++++------ dlls/ntdll/unix/security.c | 14 +++++++++++++- include/wine/server_protocol.h | 19 ++++++++++++++++++- server/process.c | 2 +- server/protocol.def | 8 ++++++++ server/request.h | 6 ++++++ server/security.h | 2 +- server/token.c | 33 +++++++++++++++++++++++++++++++-- server/trace.c | 13 +++++++++++++ 9 files changed, 96 insertions(+), 12 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 816b6418f03..8fddd635f55 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -8057,8 +8057,7 @@ static void test_elevation(void) CloseHandle(token); return; } - todo_wine ok(ret, "got error %u\n", GetLastError()); - if (!ret) return; + ok(ret, "got error %u\n", GetLastError()); if (type == TokenElevationTypeDefault) { @@ -8131,7 +8130,7 @@ static void test_elevation(void) ok(type == TokenElevationTypeLimited, "got type %#x\n", type); ret = GetTokenInformation(linked.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size); ok(ret, "got error %u\n", GetLastError()); - ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated); + todo_wine ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated); /* Asking for the linked token again gives us a different token. */ ret = GetTokenInformation(token, TokenLinkedToken, &linked2, sizeof(linked2), &size); @@ -8142,7 +8141,7 @@ static void test_elevation(void) ok(type == TokenElevationTypeLimited, "got type %#x\n", type); ret = GetTokenInformation(linked2.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size); ok(ret, "got error %u\n", GetLastError()); - ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated); + todo_wine ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated); check_different_token(linked.LinkedToken, linked2.LinkedToken); @@ -8168,12 +8167,12 @@ static void test_elevation(void) type = TokenElevationTypeLimited; ret = SetTokenInformation(token, TokenElevationType, &type, sizeof(type)); ok(!ret, "expected failure\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError()); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError()); elevation.TokenIsElevated = FALSE; ret = SetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation)); ok(!ret, "expected failure\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError()); + todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError()); } ret = DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &token2); diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index 04f1b43a5cb..c8cd04b70f3 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -167,7 +167,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c 0, /* TokenAuditPolicy */ 0, /* TokenOrigin */ sizeof(TOKEN_ELEVATION_TYPE), /* TokenElevationType */ - 0, /* TokenLinkedToken */ + sizeof(TOKEN_LINKED_TOKEN), /* TokenLinkedToken */ sizeof(TOKEN_ELEVATION), /* TokenElevation */ 0, /* TokenHasRestrictions */ 0, /* TokenAccessInformation */ @@ -476,6 +476,18 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c SERVER_END_REQ; break; + case TokenLinkedToken: + SERVER_START_REQ( create_linked_token ) + { + TOKEN_LINKED_TOKEN *linked = info; + + req->handle = wine_server_obj_handle( token ); + status = wine_server_call( req ); + if (!status) linked->LinkedToken = wine_server_ptr_handle( reply->linked ); + } + SERVER_END_REQ; + break; + default: ERR( "Unhandled token information class %u\n", class ); return STATUS_NOT_IMPLEMENTED; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index bf9536ddcc8..d475e4398a7 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4950,6 +4950,20 @@ struct get_token_elevation_reply +struct create_linked_token_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct create_linked_token_reply +{ + struct reply_header __header; + obj_handle_t linked; + char __pad_12[4]; +}; + + + struct create_completion_request { struct request_header __header; @@ -5642,6 +5656,7 @@ enum request REQ_make_process_system, REQ_get_token_statistics, REQ_get_token_elevation, + REQ_create_linked_token, REQ_create_completion, REQ_open_completion, REQ_add_completion, @@ -5924,6 +5939,7 @@ union generic_request struct make_process_system_request make_process_system_request; struct get_token_statistics_request get_token_statistics_request; struct get_token_elevation_request get_token_elevation_request; + struct create_linked_token_request create_linked_token_request; struct create_completion_request create_completion_request; struct open_completion_request open_completion_request; struct add_completion_request add_completion_request; @@ -6204,6 +6220,7 @@ union generic_reply struct make_process_system_reply make_process_system_reply; struct get_token_statistics_reply get_token_statistics_reply; struct get_token_elevation_reply get_token_elevation_reply; + struct create_linked_token_reply create_linked_token_reply; struct create_completion_reply create_completion_reply; struct open_completion_reply open_completion_reply; struct add_completion_reply add_completion_reply; @@ -6237,7 +6254,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 679 +#define SERVER_PROTOCOL_VERSION 680 /* ### protocol_version end ### */ diff --git a/server/process.c b/server/process.c index 78821593da0..e5fe7cc6b6e 100644 --- a/server/process.c +++ b/server/process.c @@ -578,7 +578,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all, if (!parent) { process->handles = alloc_handle_table( process, 0 ); - process->token = token_create_admin(); + process->token = token_create_admin( TokenElevationTypeFull ); process->affinity = ~0; } else diff --git a/server/protocol.def b/server/protocol.def index 43899bee240..2641ac86ee8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3441,6 +3441,14 @@ struct handle_info @END +/* Create a token which is an elevation counterpart to this token */ +@REQ(create_linked_token) + obj_handle_t handle; /* handle to the token */ +@REPLY + obj_handle_t linked; /* handle to the linked token */ +@END + + /* Create I/O completion port */ @REQ(create_completion) unsigned int access; /* desired access to a port */ diff --git a/server/request.h b/server/request.h index 4313b42ca52..4f2a1008024 100644 --- a/server/request.h +++ b/server/request.h @@ -365,6 +365,7 @@ DECL_HANDLER(get_kernel_object_handle); DECL_HANDLER(make_process_system); DECL_HANDLER(get_token_statistics); DECL_HANDLER(get_token_elevation); +DECL_HANDLER(create_linked_token); DECL_HANDLER(create_completion); DECL_HANDLER(open_completion); DECL_HANDLER(add_completion); @@ -646,6 +647,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_make_process_system, (req_handler)req_get_token_statistics, (req_handler)req_get_token_elevation, + (req_handler)req_create_linked_token, (req_handler)req_create_completion, (req_handler)req_open_completion, (req_handler)req_add_completion, @@ -2111,6 +2113,10 @@ C_ASSERT( FIELD_OFFSET(struct get_token_elevation_request, handle) == 12 ); C_ASSERT( sizeof(struct get_token_elevation_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_token_elevation_reply, elevation) == 8 ); C_ASSERT( sizeof(struct get_token_elevation_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_linked_token_request, handle) == 12 ); +C_ASSERT( sizeof(struct create_linked_token_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_linked_token_reply, linked) == 8 ); +C_ASSERT( sizeof(struct create_linked_token_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_completion_request, access) == 12 ); C_ASSERT( FIELD_OFFSET(struct create_completion_request, concurrent) == 16 ); C_ASSERT( sizeof(struct create_completion_request) == 24 ); diff --git a/server/security.h b/server/security.h index 08bdb8de805..416e1b6902d 100644 --- a/server/security.h +++ b/server/security.h @@ -54,7 +54,7 @@ extern const PSID security_high_label_sid; /* token functions */ extern struct token *get_token_obj( struct process *process, obj_handle_t handle, unsigned int access ); -extern struct token *token_create_admin(void); +extern struct token *token_create_admin( int elevation ); extern int token_assign_label( struct token *token, PSID label ); extern struct token *token_duplicate( struct token *src_token, unsigned primary, int impersonation_level, const struct security_descriptor *sd, diff --git a/server/token.c b/server/token.c index 5499841dd50..f7771e7174f 100644 --- a/server/token.c +++ b/server/token.c @@ -830,7 +830,7 @@ struct token *get_token_obj( struct process *process, obj_handle_t handle, unsig return (struct token *)get_handle_obj( process, handle, access, &token_ops ); } -struct token *token_create_admin( void ) +struct token *token_create_admin( int elevation ) { struct token *token = NULL; static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY }; @@ -892,7 +892,7 @@ struct token *token_create_admin( void ) static const TOKEN_SOURCE admin_source = {"SeMgr", {0, 0}}; token = create_token( TRUE, user_sid, admin_groups, ARRAY_SIZE( admin_groups ), admin_privs, ARRAY_SIZE( admin_privs ), default_dacl, - admin_source, NULL, -1, TokenElevationTypeFull ); + admin_source, NULL, -1, elevation ); /* we really need a primary group */ assert( token->primary_group ); } @@ -1679,3 +1679,32 @@ DECL_HANDLER(get_token_elevation) release_object( token ); } } + +DECL_HANDLER(create_linked_token) +{ + struct token *token, *linked; + int elevation; + + if ((token = (struct token *)get_handle_obj( current->process, req->handle, + TOKEN_QUERY, &token_ops ))) + { + switch (token->elevation) + { + case TokenElevationTypeFull: + elevation = TokenElevationTypeLimited; + break; + case TokenElevationTypeLimited: + elevation = TokenElevationTypeFull; + break; + default: + release_object( token ); + return; + } + if ((linked = token_create_admin( elevation ))) + { + reply->linked = alloc_handle( current->process, linked, TOKEN_ALL_ACCESS, 0 ); + release_object( linked ); + } + release_object( token ); + } +} diff --git a/server/trace.c b/server/trace.c index 128dd1191f8..546518b9a89 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4194,6 +4194,16 @@ static void dump_get_token_elevation_reply( const struct get_token_elevation_rep fprintf( stderr, " elevation=%d", req->elevation ); } +static void dump_create_linked_token_request( const struct create_linked_token_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_create_linked_token_reply( const struct create_linked_token_reply *req ) +{ + fprintf( stderr, " linked=%04x", req->linked ); +} + static void dump_create_completion_request( const struct create_completion_request *req ) { fprintf( stderr, " access=%08x", req->access ); @@ -4707,6 +4717,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_make_process_system_request, (dump_func)dump_get_token_statistics_request, (dump_func)dump_get_token_elevation_request, + (dump_func)dump_create_linked_token_request, (dump_func)dump_create_completion_request, (dump_func)dump_open_completion_request, (dump_func)dump_add_completion_request, @@ -4985,6 +4996,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_make_process_system_reply, (dump_func)dump_get_token_statistics_reply, (dump_func)dump_get_token_elevation_reply, + (dump_func)dump_create_linked_token_reply, (dump_func)dump_create_completion_reply, (dump_func)dump_open_completion_reply, NULL, @@ -5263,6 +5275,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "make_process_system", "get_token_statistics", "get_token_elevation", + "create_linked_token", "create_completion", "open_completion", "add_completion",