mojo: Fix map of booleans for python bindings.
[chromium-blink-merge.git] / remoting / host / win / chromoting_module.cc
blobd12ab29e4a2081005f188be1cbff4d9581530573
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/win/chromoting_module.h"
7 #include <sddl.h>
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/scoped_handle.h"
15 #include "base/win/windows_version.h"
16 #include "remoting/base/auto_thread_task_runner.h"
17 #include "remoting/base/typed_buffer.h"
18 #include "remoting/host/host_exit_codes.h"
19 #include "remoting/host/win/com_security.h"
20 #include "remoting/host/win/elevated_controller.h"
21 #include "remoting/host/win/rdp_desktop_session.h"
23 namespace remoting {
25 namespace {
27 // A security descriptor allowing local processes running under SYSTEM, built-in
28 // administrators and interactive users to call COM methods.
29 const wchar_t kElevatedControllerSd[] =
30 SDDL_OWNER L":" SDDL_BUILTIN_ADMINISTRATORS
31 SDDL_GROUP L":" SDDL_BUILTIN_ADMINISTRATORS
32 SDDL_DACL L":"
33 SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SYSTEM)
34 SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL,
35 SDDL_BUILTIN_ADMINISTRATORS)
36 SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_INTERACTIVE);
38 // Holds a reference to the task runner used by the module.
39 base::LazyInstance<scoped_refptr<AutoThreadTaskRunner> > g_module_task_runner =
40 LAZY_INSTANCE_INITIALIZER;
42 // Lowers the process integrity level such that it does not exceed |max_level|.
43 // |max_level| is expected to be one of SECURITY_MANDATORY_XXX constants.
44 bool LowerProcessIntegrityLevel(DWORD max_level) {
45 HANDLE temp_handle;
46 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_WRITE,
47 &temp_handle)) {
48 PLOG(ERROR) << "OpenProcessToken() failed";
49 return false;
51 base::win::ScopedHandle token(temp_handle);
53 TypedBuffer<TOKEN_MANDATORY_LABEL> mandatory_label;
54 DWORD length = 0;
56 // Get the size of the buffer needed to hold the mandatory label.
57 BOOL result = GetTokenInformation(token.Get(), TokenIntegrityLevel,
58 mandatory_label.get(), length, &length);
59 if (!result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
60 // Allocate a buffer that is large enough.
61 TypedBuffer<TOKEN_MANDATORY_LABEL> buffer(length);
62 mandatory_label.Swap(buffer);
64 // Get the the mandatory label.
65 result = GetTokenInformation(token.Get(), TokenIntegrityLevel,
66 mandatory_label.get(), length, &length);
68 if (!result) {
69 PLOG(ERROR) << "Failed to get the mandatory label";
70 return false;
73 // Read the current integrity level.
74 DWORD sub_authority_count =
75 *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
76 DWORD* current_level = GetSidSubAuthority(mandatory_label->Label.Sid,
77 sub_authority_count - 1);
79 // Set the integrity level to |max_level| if needed.
80 if (*current_level > max_level) {
81 *current_level = max_level;
82 if (!SetTokenInformation(token.Get(), TokenIntegrityLevel,
83 mandatory_label.get(), length)) {
84 PLOG(ERROR) << "Failed to set the mandatory label";
85 return false;
89 return true;
92 } // namespace
94 ChromotingModule::ChromotingModule(
95 ATL::_ATL_OBJMAP_ENTRY* classes,
96 ATL::_ATL_OBJMAP_ENTRY* classes_end)
97 : classes_(classes),
98 classes_end_(classes_end) {
99 // Don't do anything if COM initialization failed.
100 if (!com_initializer_.succeeded())
101 return;
103 ATL::_AtlComModule.ExecuteObjectMain(true);
106 ChromotingModule::~ChromotingModule() {
107 // Don't do anything if COM initialization failed.
108 if (!com_initializer_.succeeded())
109 return;
111 Term();
112 ATL::_AtlComModule.ExecuteObjectMain(false);
115 // static
116 scoped_refptr<AutoThreadTaskRunner> ChromotingModule::task_runner() {
117 return g_module_task_runner.Get();
120 bool ChromotingModule::Run() {
121 // Don't do anything if COM initialization failed.
122 if (!com_initializer_.succeeded())
123 return false;
125 // Register class objects.
126 HRESULT result = RegisterClassObjects(CLSCTX_LOCAL_SERVER,
127 REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
128 if (FAILED(result)) {
129 LOG(ERROR) << "Failed to register class objects, result=0x"
130 << std::hex << result << std::dec << ".";
131 return false;
134 // Arrange to run |message_loop| until no components depend on it.
135 base::MessageLoopForUI message_loop;
136 base::RunLoop run_loop;
137 g_module_task_runner.Get() = new AutoThreadTaskRunner(
138 message_loop.message_loop_proxy(), run_loop.QuitClosure());
140 // Start accepting activations.
141 result = CoResumeClassObjects();
142 if (FAILED(result)) {
143 LOG(ERROR) << "CoResumeClassObjects() failed, result=0x"
144 << std::hex << result << std::dec << ".";
145 return false;
148 // Run the loop until the module lock counter reaches zero.
149 run_loop.Run();
151 // Unregister class objects.
152 result = RevokeClassObjects();
153 if (FAILED(result)) {
154 LOG(ERROR) << "Failed to unregister class objects, result=0x"
155 << std::hex << result << std::dec << ".";
156 return false;
159 return true;
162 LONG ChromotingModule::Unlock() {
163 LONG count = ATL::CAtlModuleT<ChromotingModule>::Unlock();
165 if (!count) {
166 // Stop accepting activations.
167 HRESULT hr = CoSuspendClassObjects();
168 CHECK(SUCCEEDED(hr));
170 // Release the message loop reference, causing the message loop to exit.
171 g_module_task_runner.Get() = NULL;
174 return count;
177 HRESULT ChromotingModule::RegisterClassObjects(DWORD class_context,
178 DWORD flags) {
179 for (ATL::_ATL_OBJMAP_ENTRY* i = classes_; i != classes_end_; ++i) {
180 HRESULT result = i->RegisterClassObject(class_context, flags);
181 if (FAILED(result))
182 return result;
185 return S_OK;
188 HRESULT ChromotingModule::RevokeClassObjects() {
189 for (ATL::_ATL_OBJMAP_ENTRY* i = classes_; i != classes_end_; ++i) {
190 HRESULT result = i->RevokeClassObject();
191 if (FAILED(result))
192 return result;
195 return S_OK;
198 // Elevated controller entry point.
199 int ElevatedControllerMain() {
200 ATL::_ATL_OBJMAP_ENTRY elevated_controller_entry[] = {
201 OBJECT_ENTRY(__uuidof(ElevatedController), ElevatedController)
204 ChromotingModule module(elevated_controller_entry,
205 elevated_controller_entry + 1);
207 if (!InitializeComSecurity(base::WideToUTF8(kElevatedControllerSd), "", true))
208 return kInitializationFailed;
210 if (!module.Run())
211 return kInitializationFailed;
213 return kSuccessExitCode;
216 // RdpClient entry point.
217 int RdpDesktopSessionMain() {
218 // Lower the integrity level to medium, which is the lowest level at which
219 // the RDP ActiveX control can run.
220 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
221 if (!LowerProcessIntegrityLevel(SECURITY_MANDATORY_MEDIUM_RID))
222 return kInitializationFailed;
225 ATL::_ATL_OBJMAP_ENTRY rdp_client_entry[] = {
226 OBJECT_ENTRY(__uuidof(RdpDesktopSession), RdpDesktopSession)
229 ChromotingModule module(rdp_client_entry, rdp_client_entry + 1);
230 return module.Run() ? kSuccessExitCode : kInitializationFailed;
233 } // namespace remoting