From dd7df362ecf1c3a7483e930dd9b9c8519db47aba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 5 Aug 2017 03:39:55 +0200
Subject: [PATCH] ntdll: Implement process token elevation through manifests.

---
 dlls/ntdll/loader.c | 37 +++++++++++++++++++++++++++++++++++++
 server/process.c    |  8 ++++++++
 server/process.h    |  1 +
 server/protocol.def |  7 +++++++
 server/token.c      | 14 ++++++++++++++
 5 files changed, 67 insertions(+)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 6290cbcb4e6..9a8f13901b2 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -3489,6 +3489,32 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknow
 }
 
 
+/***********************************************************************
+ *           elevate_process
+ */
+static void elevate_process( void )
+{
+    NTSTATUS status;
+    HANDLE token;
+
+    if (!(token = __wine_create_default_token( TRUE )))
+    {
+        ERR( "Failed to create admin token\n" );
+        return;
+    }
+
+    SERVER_START_REQ( replace_process_token )
+    {
+        req->token = wine_server_obj_handle( token );
+        if ((status = wine_server_call( req )))
+            ERR( "Failed to replace process token: %08x\n", status );
+    }
+    SERVER_END_REQ;
+
+    NtClose( token );
+}
+
+
 /***********************************************************************
  *           load_global_options
  */
@@ -3900,6 +3926,7 @@ void __wine_process_init(void)
                                       'k','e','r','n','e','l','3','2','.','d','l','l',0};
     void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL;
     RTL_USER_PROCESS_PARAMETERS *params;
+    ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION runlevel;
     WINE_MODREF *wm;
     NTSTATUS status;
     ANSI_STRING func_name;
@@ -4021,6 +4048,16 @@ void __wine_process_init(void)
     }
 #endif
 
+    /* elevate process if necessary */
+    status = RtlQueryInformationActivationContext( 0, NULL, 0, RunlevelInformationInActivationContext,
+                                                   &runlevel, sizeof(runlevel), NULL );
+    if (!status && (runlevel.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE ||
+                    runlevel.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN))
+    {
+        TRACE( "Application requested admin rights (run level %d)\n", runlevel.RunLevel );
+        elevate_process();  /* FIXME: the process exists with a wrong token for a short time */
+    }
+
     /* the main exe needs to be the first in the load order list */
     RemoveEntryList( &wm->ldr.InLoadOrderLinks );
     InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderLinks );
diff --git a/server/process.c b/server/process.c
index 406167e825b..5d1248d7c4d 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1086,6 +1086,14 @@ int set_process_debug_flag( struct process *process, int flag )
     return write_process_memory( process, process->peb + 2, 1, &data );
 }
 
+/* replace the token of a process */
+void replace_process_token( struct process *process, struct token *new_token )
+{
+    release_object(current->process->token);
+    current->process->token = new_token;
+    grab_object(new_token);
+}
+
 /* create a new process */
 DECL_HANDLER(new_process)
 {
diff --git a/server/process.h b/server/process.h
index fb29f21cb12..d0b7ec4987b 100644
--- a/server/process.h
+++ b/server/process.h
@@ -129,6 +129,7 @@ extern void kill_console_processes( struct thread *renderer, int exit_code );
 extern void kill_debugged_processes( struct thread *debugger, int exit_code );
 extern void detach_debugged_processes( struct thread *debugger );
 extern void enum_processes( int (*cb)(struct process*, void*), void *user);
+extern void replace_process_token( struct process *process, struct token *token );
 
 /* console functions */
 extern void inherit_console( struct thread *parent_thread, struct process *parent,
diff --git a/server/protocol.def b/server/protocol.def
index dbc80b2d673..ed60a8da7df 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3567,6 +3567,13 @@ struct handle_info
 @END
 
 
+/* Create a new token */
+@REQ(replace_process_token)
+    obj_handle_t  token;        /* new process token */
+@REPLY
+@END
+
+
 /* Create I/O completion port */
 @REQ(create_completion)
     unsigned int access;          /* desired access to a port */
diff --git a/server/token.c b/server/token.c
index 970ed1838da..1c1d49989b3 100644
--- a/server/token.c
+++ b/server/token.c
@@ -1804,3 +1804,17 @@ DECL_HANDLER(create_token)
         release_object( token );
     }
 }
+
+/* Replaces the token of the current process  */
+DECL_HANDLER(replace_process_token)
+{
+    struct token *token;
+
+    if ((token = (struct token *)get_handle_obj( current->process, req->token,
+                                                 TOKEN_ASSIGN_PRIMARY,
+                                                 &token_ops )))
+    {
+        replace_process_token( current->process, token );
+        release_object( token );
+    }
+}
-- 
2.27.0

