Only sync parent directory once after a leveldb file rename.
[chromium-blink-merge.git] / remoting / host / win / chromoting_module.cc
blob47c76914513bc357ce1651ba0fd4c800ed04d10d
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 "base/lazy_instance.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/win/scoped_handle.h"
12 #include "base/win/windows_version.h"
13 #include "remoting/base/auto_thread_task_runner.h"
14 #include "remoting/base/typed_buffer.h"
15 #include "remoting/host/host_exit_codes.h"
16 #include "remoting/host/win/elevated_controller.h"
17 #include "remoting/host/win/rdp_desktop_session.h"
19 namespace remoting {
21 namespace {
23 // Holds a reference to the task runner used by the module.
24 base::LazyInstance<scoped_refptr<AutoThreadTaskRunner> > g_module_task_runner =
25 LAZY_INSTANCE_INITIALIZER;
27 // Lowers the process integrity level such that it does not exceed |max_level|.
28 // |max_level| is expected to be one of SECURITY_MANDATORY_XXX constants.
29 bool LowerProcessIntegrityLevel(DWORD max_level) {
30 base::win::ScopedHandle token;
31 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_WRITE,
32 token.Receive())) {
33 PLOG(ERROR) << "OpenProcessToken() failed";
34 return false;
37 TypedBuffer<TOKEN_MANDATORY_LABEL> mandatory_label;
38 DWORD length = 0;
40 // Get the size of the buffer needed to hold the mandatory label.
41 BOOL result = GetTokenInformation(token, TokenIntegrityLevel,
42 mandatory_label.get(), length, &length);
43 if (!result && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
44 // Allocate a buffer that is large enough.
45 TypedBuffer<TOKEN_MANDATORY_LABEL> buffer(length);
46 mandatory_label.Swap(buffer);
48 // Get the the mandatory label.
49 result = GetTokenInformation(token, TokenIntegrityLevel,
50 mandatory_label.get(), length, &length);
52 if (!result) {
53 PLOG(ERROR) << "Failed to get the mandatory label";
54 return false;
57 // Read the current integrity level.
58 DWORD sub_authority_count =
59 *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
60 DWORD* current_level = GetSidSubAuthority(mandatory_label->Label.Sid,
61 sub_authority_count - 1);
63 // Set the integrity level to |max_level| if needed.
64 if (*current_level > max_level) {
65 *current_level = max_level;
66 if (!SetTokenInformation(token, TokenIntegrityLevel, mandatory_label.get(),
67 length)) {
68 PLOG(ERROR) << "Failed to set the mandatory label";
69 return false;
73 return true;
76 } // namespace
78 ChromotingModule::ChromotingModule(
79 ATL::_ATL_OBJMAP_ENTRY* classes,
80 ATL::_ATL_OBJMAP_ENTRY* classes_end)
81 : classes_(classes),
82 classes_end_(classes_end) {
83 // Don't do anything if COM initialization failed.
84 if (!com_initializer_.succeeded())
85 return;
87 ATL::_AtlComModule.ExecuteObjectMain(true);
90 ChromotingModule::~ChromotingModule() {
91 // Don't do anything if COM initialization failed.
92 if (!com_initializer_.succeeded())
93 return;
95 Term();
96 ATL::_AtlComModule.ExecuteObjectMain(false);
99 // static
100 scoped_refptr<AutoThreadTaskRunner> ChromotingModule::task_runner() {
101 return g_module_task_runner.Get();
104 bool ChromotingModule::Run() {
105 // Don't do anything if COM initialization failed.
106 if (!com_initializer_.succeeded())
107 return false;
109 // Register class objects.
110 HRESULT result = RegisterClassObjects(CLSCTX_LOCAL_SERVER,
111 REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
112 if (FAILED(result)) {
113 LOG(ERROR) << "Failed to register class objects, result=0x"
114 << std::hex << result << std::dec << ".";
115 return false;
118 // Arrange to run |message_loop| until no components depend on it.
119 base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
120 base::RunLoop run_loop;
121 g_module_task_runner.Get() = new AutoThreadTaskRunner(
122 message_loop.message_loop_proxy(), run_loop.QuitClosure());
124 // Start accepting activations.
125 result = CoResumeClassObjects();
126 if (FAILED(result)) {
127 LOG(ERROR) << "CoResumeClassObjects() failed, result=0x"
128 << std::hex << result << std::dec << ".";
129 return false;
132 // Run the loop until the module lock counter reaches zero.
133 run_loop.Run();
135 // Unregister class objects.
136 result = RevokeClassObjects();
137 if (FAILED(result)) {
138 LOG(ERROR) << "Failed to unregister class objects, result=0x"
139 << std::hex << result << std::dec << ".";
140 return false;
143 return true;
146 LONG ChromotingModule::Unlock() {
147 LONG count = ATL::CAtlModuleT<ChromotingModule>::Unlock();
149 if (!count) {
150 // Stop accepting activations.
151 HRESULT hr = CoSuspendClassObjects();
152 CHECK(SUCCEEDED(hr));
154 // Release the message loop reference, causing the message loop to exit.
155 g_module_task_runner.Get() = NULL;
158 return count;
161 HRESULT ChromotingModule::RegisterClassObjects(DWORD class_context,
162 DWORD flags) {
163 for (ATL::_ATL_OBJMAP_ENTRY* i = classes_; i != classes_end_; ++i) {
164 HRESULT result = i->RegisterClassObject(class_context, flags);
165 if (FAILED(result))
166 return result;
169 return S_OK;
172 HRESULT ChromotingModule::RevokeClassObjects() {
173 for (ATL::_ATL_OBJMAP_ENTRY* i = classes_; i != classes_end_; ++i) {
174 HRESULT result = i->RevokeClassObject();
175 if (FAILED(result))
176 return result;
179 return S_OK;
182 // Elevated controller entry point.
183 int ElevatedControllerMain() {
184 ATL::_ATL_OBJMAP_ENTRY elevated_controller_entry[] = {
185 OBJECT_ENTRY(__uuidof(ElevatedController), ElevatedController)
188 ChromotingModule module(elevated_controller_entry,
189 elevated_controller_entry + 1);
190 return module.Run() ? kSuccessExitCode : kInitializationFailed;
193 // RdpClient entry point.
194 int RdpDesktopSessionMain() {
195 // Lower the integrity level to medium, which is the lowest level at which
196 // the RDP ActiveX control can run.
197 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
198 if (!LowerProcessIntegrityLevel(SECURITY_MANDATORY_MEDIUM_RID))
199 return kInitializationFailed;
202 ATL::_ATL_OBJMAP_ENTRY rdp_client_entry[] = {
203 OBJECT_ENTRY(__uuidof(RdpDesktopSession), RdpDesktopSession)
206 ChromotingModule module(rdp_client_entry, rdp_client_entry + 1);
207 return module.Run() ? kSuccessExitCode : kInitializationFailed;
210 } // namespace remoting