blob: 7cd7706c7b3f87c7886f1c24bbc7b279346bfd75 [file] [log] [blame]
[email protected]3e76e27b2011-05-02 21:19:011// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]f7817822009-09-24 05:11:582// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// chrome_tab.cc : Implementation of DLL Exports.
[email protected]3f55e872009-10-17 04:48:376
7// Include without path to make GYP build see it.
8#include "chrome_tab.h" // NOLINT
9
10#include <atlsecurity.h>
[email protected]848bdf22011-09-23 20:48:5811#include <objbase.h>
[email protected]3f55e872009-10-17 04:48:3712
[email protected]f7817822009-09-24 05:11:5813#include "base/at_exit.h"
14#include "base/command_line.h"
15#include "base/file_util.h"
16#include "base/file_version_info.h"
17#include "base/logging.h"
[email protected]5ee34132009-11-25 21:32:2618#include "base/logging_win.h"
[email protected]f7817822009-09-24 05:11:5819#include "base/path_service.h"
[email protected]c9c077792010-08-03 14:39:4220#include "base/string_number_conversions.h"
[email protected]f7817822009-09-24 05:11:5821#include "base/string_piece.h"
22#include "base/string_util.h"
23#include "base/sys_string_conversions.h"
[email protected]2d6503982010-10-17 04:41:5424#include "base/win/registry.h"
[email protected]935aa542010-10-15 01:59:1525#include "base/win/windows_version.h"
[email protected]f7817822009-09-24 05:11:5826#include "chrome/common/chrome_constants.h"
[email protected]02ea78a2010-07-15 16:52:2827#include "chrome/common/chrome_switches.h"
28#include "chrome/installer/util/google_update_settings.h"
[email protected]f7817822009-09-24 05:11:5829#include "chrome_frame/bho.h"
[email protected]ea9ed97d2010-01-05 19:16:2330#include "chrome_frame/chrome_active_document.h"
31#include "chrome_frame/chrome_frame_activex.h"
[email protected]f7817822009-09-24 05:11:5832#include "chrome_frame/chrome_frame_automation.h"
[email protected]53556e12009-10-15 21:49:2233#include "chrome_frame/chrome_frame_reporting.h"
[email protected]79b663c2010-05-28 17:27:1734#include "chrome_frame/chrome_launcher_utils.h"
[email protected]ea9ed97d2010-01-05 19:16:2335#include "chrome_frame/chrome_protocol.h"
[email protected]c6352e92010-12-03 01:57:4736#include "chrome_frame/dll_redirector.h"
37#include "chrome_frame/exception_barrier.h"
[email protected]f7817822009-09-24 05:11:5838#include "chrome_frame/resource.h"
39#include "chrome_frame/utils.h"
[email protected]cebd4132010-03-25 15:34:2240#include "googleurl/src/url_util.h"
[email protected]c6352e92010-12-03 01:57:4741#include "grit/chrome_frame_resources.h"
[email protected]cebd4132010-03-25 15:34:2242
[email protected]2d6503982010-10-17 04:41:5443using base::win::RegKey;
44
[email protected]cebd4132010-03-25 15:34:2245namespace {
46// This function has the side effect of initializing an unprotected
47// vector pointer inside GoogleUrl. If this is called during DLL loading,
[email protected]59b34a72010-09-01 17:30:3548// it has the effect of avoiding an initialization race on that pointer.
[email protected]cebd4132010-03-25 15:34:2249// TODO(siggi): fix GoogleUrl.
50void InitGoogleUrl() {
51 static const char kDummyUrl[] = "http://www.google.com";
52
53 url_util::IsStandard(kDummyUrl,
54 url_parse::MakeRange(0, arraysize(kDummyUrl)));
55}
[email protected]f7817822009-09-24 05:11:5856
[email protected]357219de2009-10-06 23:40:2257const wchar_t kInternetSettings[] =
58 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
59
[email protected]552fb6012010-02-03 17:24:2960const wchar_t kProtocolHandlers[] =
61 L"Software\\Classes\\Protocols\\Handler";
62
[email protected]02ea78a2010-07-15 16:52:2863const wchar_t kRunOnce[] =
64 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
65
[email protected]c5c6c8c2010-09-07 13:57:2166const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
67
68const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
[email protected]6a7748e2011-05-27 16:44:3169const wchar_t kChromeFrameHelperStartupArg[] = L"--startup";
[email protected]c5c6c8c2010-09-07 13:57:2170
71// Window class and window names.
72// TODO(robertshield): These and other constants need to be refactored into
73// a common chrome_frame_constants.h|cc and built into a separate lib
74// (either chrome_frame_utils or make another one).
75const wchar_t kChromeFrameHelperWindowClassName[] =
76 L"ChromeFrameHelperWindowClass";
77const wchar_t kChromeFrameHelperWindowName[] =
78 L"ChromeFrameHelperWindowName";
[email protected]f7817822009-09-24 05:11:5879
[email protected]5ee34132009-11-25 21:32:2680// {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
81static const GUID kChromeFrameProvider =
82 { 0x562bfc3, 0x2550, 0x45b4,
83 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
84
[email protected]9f7b8602011-09-08 19:45:4585const wchar_t kPostPlatformUAKey[] =
86 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
87 L"User Agent\\Post Platform";
88const wchar_t kChromeFramePrefix[] = L"chromeframe/";
[email protected]8adbf7e52010-04-14 20:03:2389
90// See comments in DllGetClassObject.
[email protected]52749842010-05-07 21:34:4191LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
[email protected]8adbf7e52010-04-14 20:03:2392
[email protected]6bdc0c02010-07-20 14:52:1393class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
[email protected]f7817822009-09-24 05:11:5894 public:
[email protected]6bdc0c02010-07-20 14:52:1395 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
[email protected]f7817822009-09-24 05:11:5896
[email protected]59b34a72010-09-01 17:30:3597 ChromeTabModule() : do_system_registration_(true) {}
98
[email protected]f7817822009-09-24 05:11:5899 DECLARE_LIBID(LIBID_ChromeTabLib)
100 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
101 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
102
103 // Override to add our SYSTIME binary value to registry scripts.
104 // See chrome_frame_activex.rgs for usage.
105 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
106 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
107
108 if (SUCCEEDED(hr)) {
109 SYSTEMTIME local_time;
110 ::GetSystemTime(&local_time);
[email protected]c9c077792010-08-03 14:39:42111 std::string hex(base::HexEncode(&local_time, sizeof(local_time)));
[email protected]f7817822009-09-24 05:11:58112 base::StringPiece sp_hex(hex);
113 hr = registrar->AddReplacement(L"SYSTIME",
114 base::SysNativeMBToWide(sp_hex).c_str());
115 DCHECK(SUCCEEDED(hr));
116 }
117
118 if (SUCCEEDED(hr)) {
[email protected]66ff7352009-10-15 05:09:50119 FilePath app_path =
120 chrome_launcher::GetChromeExecutablePath().DirName();
121 hr = registrar->AddReplacement(L"CHROME_APPPATH",
122 app_path.value().c_str());
[email protected]f7817822009-09-24 05:11:58123 DCHECK(SUCCEEDED(hr));
124 }
125
126 if (SUCCEEDED(hr)) {
127 hr = registrar->AddReplacement(L"CHROME_APPNAME",
128 chrome::kBrowserProcessExecutableName);
129 DCHECK(SUCCEEDED(hr));
130
131 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
132 scoped_ptr<FileVersionInfo> module_version_info(
133 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
134 DCHECK(module_version_info != NULL);
135 std::wstring file_version(module_version_info->file_version());
136 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
137 DCHECK(SUCCEEDED(hr));
138 }
139
140 if (SUCCEEDED(hr)) {
141 // Add the directory of chrome_launcher.exe. This will be the same
142 // as the directory for the current DLL.
143 std::wstring module_dir;
144 FilePath module_path;
145 if (PathService::Get(base::FILE_MODULE, &module_path)) {
[email protected]466a9222010-06-08 01:03:16146 module_dir = module_path.DirName().value();
[email protected]f7817822009-09-24 05:11:58147 } else {
148 NOTREACHED();
149 }
150 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
151 module_dir.c_str());
152 DCHECK(SUCCEEDED(hr));
153 }
154
155 if (SUCCEEDED(hr)) {
156 // Add the filename of chrome_launcher.exe
157 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
158 chrome_launcher::kLauncherExeBaseName);
159 DCHECK(SUCCEEDED(hr));
160 }
161
[email protected]59b34a72010-09-01 17:30:35162 if (SUCCEEDED(hr)) {
163 // Add the registry hive to use.
164 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
165 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
166 // few components that are registered by calling their
167 // static T::UpdateRegistry() methods directly, which doesn't allow
168 // pMapEntries to be passed through :-(
169 if (do_system_registration_) {
170 hr = registrar->AddReplacement(L"HIVE", L"HKLM");
171 } else {
172 hr = registrar->AddReplacement(L"HIVE", L"HKCU");
173 }
174 DCHECK(SUCCEEDED(hr));
175 }
176
[email protected]848bdf22011-09-23 20:48:58177 if (SUCCEEDED(hr)) {
178 // Add the Chrome Frame CLSID.
179 wchar_t cf_clsid[64];
180 StringFromGUID2(CLSID_ChromeFrame, &cf_clsid[0], arraysize(cf_clsid));
181 hr = registrar->AddReplacement(L"CHROME_FRAME_CLSID", &cf_clsid[0]);
182 }
183
[email protected]f7817822009-09-24 05:11:58184 return hr;
185 }
[email protected]59b34a72010-09-01 17:30:35186
187 // See comments in AddCommonRGSReplacements
188 bool do_system_registration_;
[email protected]f7817822009-09-24 05:11:58189};
190
191ChromeTabModule _AtlModule;
192
193base::AtExitManager* g_exit_manager = NULL;
194
[email protected]f7817822009-09-24 05:11:58195
[email protected]f7817822009-09-24 05:11:58196HRESULT RefreshElevationPolicy() {
197 const wchar_t kIEFrameDll[] = L"ieframe.dll";
198 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
199 HRESULT hr = E_NOTIMPL;
[email protected]1f08d682010-05-19 18:48:31200
201 // Stick an SEH in the chain to prevent the VEH from picking up on first
202 // chance exceptions caused by loading ieframe.dll. Use the vanilla
203 // ExceptionBarrier to report any exceptions that do make their way to us
204 // though.
205 ExceptionBarrier barrier;
206
[email protected]f7817822009-09-24 05:11:58207 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
208 if (ieframe_module) {
209 typedef HRESULT (__stdcall *IERefreshPolicy)();
210 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
211 GetProcAddress(ieframe_module, kIERefreshPolicy));
212
213 if (ie_refresh_policy) {
214 hr = ie_refresh_policy();
215 } else {
216 hr = HRESULT_FROM_WIN32(GetLastError());
217 }
[email protected]357219de2009-10-06 23:40:22218
[email protected]f7817822009-09-24 05:11:58219 FreeLibrary(ieframe_module);
220 } else {
221 hr = HRESULT_FROM_WIN32(GetLastError());
222 }
223
224 return hr;
225}
226
[email protected]02ea78a2010-07-15 16:52:28227// Experimental boot prefetch optimization for Chrome Frame
228//
229// If chrome is warmed up during a single reboot, it gets paged
230// in for subsequent reboots and the cold startup times essentially
231// look like warm times thereafter! The 'warm up' is done by
232// setting up a 'RunOnce' key during DLLRegisterServer of
233// npchrome_frame.dll.
234//
235// This works because chrome prefetch becomes part of boot
236// prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
237// reboots. As long as the sytem does not undergo significant
238// memory pressure those pages remain in memory and we get pretty
239// amazing startup times, down to about 300 ms from 1200 ms
240//
241// The downside is:
242// - Whether chrome frame is used or not, there's a read penalty
243// (1200-300 =) 900 ms for every boot.
244// - Heavy system memory usage after reboot will nullify the benefits
245// but the user will still pay the cost.
246// - Overall the time saved will always be less than total time spent
247// paging in chrome
248// - We are not sure when the chrome 'warm up' will age out from the
249// boot prefetch file.
250//
251// The idea here is to try this out on chrome frame dev channel
252// and see if it produces a significant drift in startup numbers.
253HRESULT SetupRunOnce() {
[email protected]7fc3e6922010-11-18 17:56:54254 HRESULT result = E_FAIL;
[email protected]02ea78a2010-07-15 16:52:28255
256 std::wstring channel_name;
[email protected]7fc3e6922010-11-18 17:56:54257 if (base::win::GetVersion() < base::win::VERSION_VISTA &&
[email protected]3e76e27b2011-05-02 21:19:01258 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name)) {
[email protected]7fc3e6922010-11-18 17:56:54259 std::transform(channel_name.begin(), channel_name.end(),
260 channel_name.begin(), tolower);
261 // Use this only for the dev channel and CEEE channels.
262 if (channel_name.find(L"dev") != std::wstring::npos ||
263 channel_name.find(L"ceee") != std::wstring::npos) {
[email protected]7fc3e6922010-11-18 17:56:54264 HKEY hive = HKEY_CURRENT_USER;
265 if (IsSystemProcess()) {
266 // For system installs, our updates will be running as SYSTEM which
267 // makes writing to a RunOnce key under HKCU not so terribly useful.
268 hive = HKEY_LOCAL_MACHINE;
269 }
[email protected]74ecb5a42010-09-03 00:44:35270
[email protected]7fc3e6922010-11-18 17:56:54271 RegKey run_once;
[email protected]e06f4d52011-01-19 07:28:46272 LONG ret = run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE);
273 if (ret == ERROR_SUCCESS) {
[email protected]7fc3e6922010-11-18 17:56:54274 CommandLine run_once_cmd(chrome_launcher::GetChromeExecutablePath());
275 run_once_cmd.AppendSwitchASCII(switches::kAutomationClientChannelID,
[email protected]05076ba22010-07-30 05:59:57276 "0");
[email protected]7fc3e6922010-11-18 17:56:54277 run_once_cmd.AppendSwitch(switches::kChromeFrame);
[email protected]e06f4d52011-01-19 07:28:46278 ret = run_once.WriteValue(L"A",
[email protected]61a4c6f2011-07-20 04:54:52279 run_once_cmd.GetCommandLineString().c_str());
[email protected]7fc3e6922010-11-18 17:56:54280 }
[email protected]e06f4d52011-01-19 07:28:46281 result = HRESULT_FROM_WIN32(ret);
[email protected]7fc3e6922010-11-18 17:56:54282 } else {
283 result = S_FALSE;
284 }
285 } else {
286 // We're on a non-XP version of Windows or on a stable channel. Nothing
287 // needs doing.
288 result = S_FALSE;
[email protected]552fb6012010-02-03 17:24:29289 }
290
[email protected]7fc3e6922010-11-18 17:56:54291 return result;
[email protected]552fb6012010-02-03 17:24:29292}
293
[email protected]c5c6c8c2010-09-07 13:57:21294// Helper method called for user-level installs where we don't have admin
295// permissions. Starts up the long running process and registers it to get it
296// started at next boot.
[email protected]9f7b8602011-09-08 19:45:45297HRESULT SetupUserLevelHelper() {
298 HRESULT hr = S_OK;
299
[email protected]c5c6c8c2010-09-07 13:57:21300 // Remove existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50301 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21302
303 // Build the chrome_frame_helper command line.
304 FilePath module_path;
305 FilePath helper_path;
306 if (PathService::Get(base::FILE_MODULE, &module_path)) {
307 module_path = module_path.DirName();
308 helper_path = module_path.Append(kChromeFrameHelperExe);
309 if (!file_util::PathExists(helper_path)) {
310 // If we can't find the helper in the current directory, try looking
311 // one up (this is the layout in the build output folder).
312 module_path = module_path.DirName();
313 helper_path = module_path.Append(kChromeFrameHelperExe);
314 DCHECK(file_util::PathExists(helper_path)) <<
315 "Could not find chrome_frame_helper.exe.";
316 }
[email protected]9f7b8602011-09-08 19:45:45317
318 // Find window handle of existing instance.
319 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
320 kChromeFrameHelperWindowName);
321
322 if (file_util::PathExists(helper_path)) {
323 std::wstring helper_path_cmd(L"\"");
324 helper_path_cmd += helper_path.value();
325 helper_path_cmd += L"\" ";
326 helper_path_cmd += kChromeFrameHelperStartupArg;
327
328 // Add new run-at-startup entry.
329 if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
330 helper_path_cmd)) {
331 hr = E_FAIL;
332 LOG(ERROR) << "Could not add helper process to auto run key.";
333 }
334
335 // Start new instance.
336 base::LaunchOptions options;
337 options.start_hidden = true;
338 bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
339 if (!launched) {
340 hr = E_FAIL;
341 PLOG(DFATAL) << "Could not launch helper process.";
342 }
343
344 // Kill old instance using window handle.
345 if (IsWindow(old_window)) {
346 BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
347 if (!result) {
348 PLOG(ERROR) << "Failed to post close message to old helper process: ";
349 }
350 }
351 } else {
352 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
353 }
[email protected]c5c6c8c2010-09-07 13:57:21354 } else {
[email protected]9f7b8602011-09-08 19:45:45355 hr = E_UNEXPECTED;
[email protected]c5c6c8c2010-09-07 13:57:21356 NOTREACHED();
357 }
358
[email protected]9f7b8602011-09-08 19:45:45359 return hr;
[email protected]c5c6c8c2010-09-07 13:57:21360}
361
[email protected]6a8515e42010-12-16 19:38:52362// To delete the user agent, set value to NULL.
363// The is_system parameter indicates whether this is a per machine or a per
364// user installation.
365HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
366 HRESULT hr = E_FAIL;
367 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
368
369 RegKey ua_key;
[email protected]9f7b8602011-09-08 19:45:45370 LONG reg_result = ua_key.Create(parent_hive, kPostPlatformUAKey,
371 KEY_READ | KEY_WRITE);
372 if (reg_result == ERROR_SUCCESS) {
[email protected]45b716b2011-01-14 18:43:53373 // Make sure that we unregister ChromeFrame UA strings registered previously
[email protected]9b7baa962011-01-14 20:07:07374 wchar_t value_name[MAX_PATH + 1] = {};
375 wchar_t value_data[MAX_PATH + 1] = {};
[email protected]45b716b2011-01-14 18:43:53376
377 DWORD value_index = 0;
378 while (value_index < ua_key.ValueCount()) {
[email protected]9b7baa962011-01-14 20:07:07379 DWORD name_size = arraysize(value_name);
380 DWORD value_size = arraysize(value_data);
[email protected]45b716b2011-01-14 18:43:53381 DWORD type = 0;
[email protected]9b7baa962011-01-14 20:07:07382 LRESULT ret = ::RegEnumValue(ua_key.Handle(), value_index, value_name,
[email protected]45b716b2011-01-14 18:43:53383 &name_size, NULL, &type,
[email protected]9b7baa962011-01-14 20:07:07384 reinterpret_cast<BYTE*>(value_data),
[email protected]45b716b2011-01-14 18:43:53385 &value_size);
386 if (ret == ERROR_SUCCESS) {
[email protected]9b7baa962011-01-14 20:07:07387 if (StartsWith(value_name, kChromeFramePrefix, false)) {
388 ua_key.DeleteValue(value_name);
[email protected]45b716b2011-01-14 18:43:53389 } else {
390 ++value_index;
391 }
392 } else {
393 break;
394 }
395 }
396
[email protected]6a8515e42010-12-16 19:38:52397 std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
398 chrome_frame_ua_value_name += GetCurrentModuleVersion();
399 if (value) {
400 ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value);
[email protected]6a8515e42010-12-16 19:38:52401 }
402 hr = S_OK;
403 } else {
[email protected]9f7b8602011-09-08 19:45:45404 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey
405 << ", error code = " << reg_result;
406 hr = HRESULT_FROM_WIN32(reg_result);
[email protected]6a8515e42010-12-16 19:38:52407 }
408 return hr;
409}
410
[email protected]357219de2009-10-06 23:40:22411class SecurityDescBackup {
412 public:
413 explicit SecurityDescBackup(const std::wstring& backup_key)
414 : backup_key_name_(backup_key) {}
415 ~SecurityDescBackup() {}
416
417 // Save given security descriptor to the backup key.
418 bool SaveSecurity(const CSecurityDesc& sd) {
419 CString str;
420 if (!sd.ToString(&str))
421 return false;
422
423 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
424 KEY_READ | KEY_WRITE);
425 if (backup_key.Valid()) {
[email protected]e06f4d52011-01-19 07:28:46426 return backup_key.WriteValue(NULL, str.GetString()) == ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22427 }
428
429 return false;
430 }
431
432 // Restore security descriptor from backup key to given key name.
433 bool RestoreSecurity(const wchar_t* key_name) {
434 std::wstring sddl;
435 if (!ReadBackupKey(&sddl))
436 return false;
437
438 // Create security descriptor from string.
439 CSecurityDesc sd;
440 if (!sd.FromString(sddl.c_str()))
441 return false;
442
443 bool result = true;
444 // Restore DACL and Owner of the key from saved security descriptor.
445 CDacl dacl;
446 CSid owner;
447 sd.GetDacl(&dacl);
448 sd.GetOwner(&owner);
449
450 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
451 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
452 const_cast<SID*>(owner.GetPSID()), NULL,
453 const_cast<ACL*>(dacl.GetPACL()), NULL);
454
455 DeleteBackupKey();
456 return (error == ERROR_SUCCESS);
457 }
458
459 private:
460 // Read SDDL string from backup key
461 bool ReadBackupKey(std::wstring* sddl) {
462 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
463 if (!backup_key.Valid())
464 return false;
465
466 DWORD len = 0;
467 DWORD reg_type = REG_NONE;
[email protected]e06f4d52011-01-19 07:28:46468 if (backup_key.ReadValue(NULL, NULL, &len, &reg_type) != ERROR_SUCCESS)
[email protected]357219de2009-10-06 23:40:22469 return false;
470
471 if (reg_type != REG_SZ)
472 return false;
473
474 size_t wchar_count = 1 + len / sizeof(wchar_t);
[email protected]e06f4d52011-01-19 07:28:46475 if (backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
476 &reg_type) != ERROR_SUCCESS) {
[email protected]357219de2009-10-06 23:40:22477 return false;
478 }
479
480 return true;
481 }
482
483 void DeleteBackupKey() {
484 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
485 }
486
487 std::wstring backup_key_name_;
488};
489
490struct TokenWithPrivileges {
491 TokenWithPrivileges() {
492 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
493 token_.GetUser(&user_);
494 }
495
496 ~TokenWithPrivileges() {
497 token_.EnableDisablePrivileges(take_ownership_);
498 token_.EnableDisablePrivileges(restore_);
499 }
500
501 bool EnablePrivileges() {
502 if (take_ownership_.GetCount() == 0)
503 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
504 &take_ownership_))
505 return false;
506
507 if (restore_.GetCount() == 0)
508 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
509 return false;
510
511 return true;
512 }
513
514 const CSid& GetUser() const {
515 return user_;
516 }
517
518 private:
519 CAccessToken token_;
520 CTokenPrivileges take_ownership_;
521 CTokenPrivileges restore_;
522 CSid user_;
523};
524
[email protected]9f7b8602011-09-08 19:45:45525HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
[email protected]357219de2009-10-06 23:40:22526 std::wstring key_name = kInternetSettings;
527 key_name.append(L"\\Secure Mime Handlers");
[email protected]59b34a72010-09-01 17:30:35528 RegKey key(root_key, key_name.c_str(), KEY_READ | KEY_WRITE);
[email protected]357219de2009-10-06 23:40:22529 if (!key.Valid())
530 return false;
531
[email protected]e06f4d52011-01-19 07:28:46532 LONG result1 = ERROR_SUCCESS;
533 LONG result2 = ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22534 if (set) {
[email protected]e06f4d52011-01-19 07:28:46535 result1 = key.WriteValue(L"ChromeTab.ChromeActiveDocument", 1);
536 result2 = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1);
[email protected]357219de2009-10-06 23:40:22537 } else {
[email protected]e06f4d52011-01-19 07:28:46538 result1 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
539 result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1");
[email protected]357219de2009-10-06 23:40:22540 }
541
[email protected]9f7b8602011-09-08 19:45:45542 return result1 != ERROR_SUCCESS ? HRESULT_FROM_WIN32(result1) :
543 HRESULT_FROM_WIN32(result2);
[email protected]357219de2009-10-06 23:40:22544}
545
[email protected]9f7b8602011-09-08 19:45:45546// Chrome Frame registration functions.
547//-----------------------------------------------------------------------------
548HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
[email protected]59b34a72010-09-01 17:30:35549 if (!is_system) {
550 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
[email protected]935aa542010-10-15 01:59:15551 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
[email protected]59b34a72010-09-01 17:30:35552 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22553 }
554
555 std::wstring mime_key = kInternetSettings;
556 mime_key.append(L"\\Secure Mime Handlers");
557 std::wstring backup_key = kInternetSettings;
558 backup_key.append(L"\\__backup_SMH__");
559 std::wstring object_name = L"MACHINE\\";
560 object_name.append(mime_key);
561
562 TokenWithPrivileges token_;
563 if (!token_.EnablePrivileges())
[email protected]9f7b8602011-09-08 19:45:45564 return E_ACCESSDENIED;
[email protected]357219de2009-10-06 23:40:22565
566 // If there is a backup key - something bad happened; try to restore
567 // security on "Secure Mime Handlers" from the backup.
568 SecurityDescBackup backup(backup_key);
569 backup.RestoreSecurity(object_name.c_str());
570
571 // Read old security descriptor of the Mime key first.
572 CSecurityDesc sd;
573 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
[email protected]9f7b8602011-09-08 19:45:45574 return E_FAIL;
[email protected]357219de2009-10-06 23:40:22575 }
576
577 backup.SaveSecurity(sd);
[email protected]9f7b8602011-09-08 19:45:45578 HRESULT hr = E_FAIL;
[email protected]357219de2009-10-06 23:40:22579 // set new owner
580 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
581 // set new dacl
582 CDacl new_dacl;
583 sd.GetDacl(&new_dacl);
584 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
585 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
[email protected]9f7b8602011-09-08 19:45:45586 hr = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22587 }
588 }
589
590 backup.RestoreSecurity(object_name.c_str());
[email protected]9f7b8602011-09-08 19:45:45591 return hr;
[email protected]357219de2009-10-06 23:40:22592}
[email protected]9f7b8602011-09-08 19:45:45593
594HRESULT RegisterActiveDoc(bool reg, bool is_system) {
595 // We have to call the static T::UpdateRegistry function instead of
596 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg)
597 // because there is specific OLEMISC replacement.
598 return ChromeActiveDocument::UpdateRegistry(reg);
599}
600
601HRESULT RegisterActiveX(bool reg, bool is_system) {
602 // We have to call the static T::UpdateRegistry function instead of
603 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
604 // because there is specific OLEMISC replacement.
605 return ChromeFrameActivex::UpdateRegistry(reg);
606}
607
608HRESULT RegisterElevationPolicy(bool reg, bool is_system) {
609 HRESULT hr = S_OK;
[email protected]848bdf22011-09-23 20:48:58610 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
[email protected]9f7b8602011-09-08 19:45:45611 // Register the elevation policy. This must succeed for Chrome Frame to
612 // be able launch Chrome when running in low-integrity IE.
[email protected]848bdf22011-09-23 20:48:58613 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION, reg);
[email protected]9f7b8602011-09-08 19:45:45614 if (SUCCEEDED(hr)) {
615 hr = RefreshElevationPolicy();
616 }
617 }
618 return hr;
619}
620
621HRESULT RegisterProtocol(bool reg, bool is_system) {
622 return _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
623}
624
625HRESULT RegisterBhoClsid(bool reg, bool is_system) {
626 return Bho::UpdateRegistry(reg);
627}
628
629HRESULT RegisterBhoIE(bool reg, bool is_system) {
630 if (is_system) {
631 return _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
632 } else {
633 if (reg) {
634 // Setup the long running process:
635 return SetupUserLevelHelper();
636 } else {
637 // Unschedule the user-level helper. Note that we don't kill it here
638 // so that during updates we don't have a time window with no running
639 // helper. Uninstalls and updates will explicitly kill the helper from
640 // within the installer. Unregister existing run-at-startup entry.
641 return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER,
642 kRunKeyName) ? S_OK : E_FAIL;
643 }
644 }
645}
646
647HRESULT RegisterTypeLib(bool reg, bool is_system) {
648 if (reg && !is_system) {
649 // Enables the RegisterTypeLib Function function to override default
650 // registry mappings under Windows Vista Service Pack 1 (SP1),
651 // Windows Server 2008, and later operating system versions
652 typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
653 OaEnablePerUserTypeLibReg per_user_typelib_func =
654 reinterpret_cast<OaEnablePerUserTypeLibReg>(
655 GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
656 "OaEnablePerUserTLibRegistration"));
657 if (per_user_typelib_func) {
658 (*per_user_typelib_func)();
659 }
660 }
661 return reg ?
662 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
663 NULL, !is_system) :
664 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
665 NULL, !is_system);
666}
667
668HRESULT RegisterLegacyNPAPICleanup(bool reg, bool is_system) {
669 if (!reg) {
670 _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
671 UtilRemovePersistentNPAPIMarker();
672 }
673 // Ignore failures.
674 return S_OK;
675}
676
677HRESULT RegisterAppId(bool reg, bool is_system) {
678 return _AtlModule.UpdateRegistryAppId(reg);
679}
680
681HRESULT RegisterUserAgent(bool reg, bool is_system) {
682 if (reg) {
683 return SetChromeFrameUA(is_system, L"1");
684 } else {
685 return SetChromeFrameUA(is_system, NULL);
686 }
687}
688
689enum RegistrationStepId {
690 kStepSecuredMimeHandler = 0,
691 kStepActiveDoc = 1,
692 kStepActiveX = 2,
693 kStepElevationPolicy = 3,
694 kStepProtocol = 4,
695 kStepBhoClsid = 5,
696 kStepBhoRegistration = 6,
697 kStepRegisterTypeLib = 7,
698 kStepNpapiCleanup = 8,
699 kStepAppId = 9,
700 kStepUserAgent = 10,
701 kStepEnd = 11
702};
703
704enum RegistrationFlags {
705 ACTIVEX = 0x0001,
706 ACTIVEDOC = 0x0002,
707 GCF_PROTOCOL = 0x0004,
708 BHO_CLSID = 0x0008,
709 BHO_REGISTRATION = 0x0010,
710 TYPELIB = 0x0020,
711
712 ALL = 0xFFFF
713};
714
715// Mux the failure step into the hresult. We take only the first four bits
716// and stick those into the top four bits of the facility code. We also set the
717// Customer bit to be polite. Graphically, we write our error code to the
718// bits marked with ^:
719// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
720// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
721// +---+-+-+-----------------------+-------------------------------+
722// |Sev|C|R| Facility | Code |
723// +---+-+-+-----------------------+-------------------------------+
724// ^ ^ ^ ^ ^
725// See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for
726// more details on HRESULTS.
727//
728// The resulting error can be extracted by:
729// error_code = (fiddled_hr & 0x07800000) >> 23
730HRESULT MuxErrorIntoHRESULT(HRESULT hr, int error_code) {
731 DCHECK_GE(error_code, 0);
732 DCHECK_LT(error_code, kStepEnd);
733 COMPILE_ASSERT(kStepEnd <= 0xF, update_error_muxing_too_many_steps);
734
735 // Check that our four desired bits are clear.
736 // 0xF87FFFFF == 11111000011111111111111111111111
737 DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr);
738
739 HRESULT fiddled_hr = ((error_code & 0xF) << 23) | hr;
740 fiddled_hr |= 1 << 29; // Set the customer bit.
741
742 return fiddled_hr;
743}
744
745HRESULT CustomRegistration(uint16 reg_flags, bool reg, bool is_system) {
746 if (reg && (reg_flags & (ACTIVEDOC | ACTIVEX)))
747 reg_flags |= (TYPELIB | GCF_PROTOCOL);
748
749 // Set the flag that gets checked in AddCommonRGSReplacements before doing
750 // registration work.
751 _AtlModule.do_system_registration_ = is_system;
752
753 typedef HRESULT (*RegistrationFn)(bool reg, bool is_system);
754 struct RegistrationStep {
755 RegistrationStepId id;
756 uint16 condition;
757 RegistrationFn func;
758 };
759 static const RegistrationStep registration_steps[] = {
760 { kStepSecuredMimeHandler, ACTIVEDOC, &RegisterSecuredMimeHandler },
761 { kStepActiveDoc, ACTIVEDOC, &RegisterActiveDoc },
762 { kStepActiveX, ACTIVEX, &RegisterActiveX },
763 { kStepElevationPolicy, (ACTIVEDOC | ACTIVEX), &RegisterElevationPolicy },
764 { kStepProtocol, GCF_PROTOCOL, &RegisterProtocol },
765 { kStepBhoClsid, BHO_CLSID, &RegisterBhoClsid },
766 { kStepBhoRegistration, BHO_REGISTRATION, &RegisterBhoIE },
767 { kStepRegisterTypeLib, TYPELIB, &RegisterTypeLib },
768 { kStepNpapiCleanup, ALL, &RegisterLegacyNPAPICleanup },
769 { kStepAppId, ALL, &RegisterAppId },
770 { kStepUserAgent, ALL, &RegisterUserAgent }
771 };
772
773 HRESULT hr = S_OK;
774
775 bool rollback = false;
776 int failure_step = 0;
777 HRESULT step_hr = S_OK;
778 for (int step = 0; step < arraysize(registration_steps); ++step) {
779 if ((reg_flags & registration_steps[step].condition) != 0) {
780 step_hr = registration_steps[step].func(reg, is_system);
781 if (FAILED(step_hr)) {
782 // Store only the first failing HRESULT with the step value muxed in.
783 if (hr == S_OK) {
784 hr = MuxErrorIntoHRESULT(step_hr, step);
785 }
786
787 // On registration if a step fails, we abort and rollback.
788 if (reg) {
789 rollback = true;
790 failure_step = step;
791 break;
792 }
793 }
794 }
795 }
796
797 if (rollback) {
798 DCHECK(reg);
799 // Rollback the failing action and all preceding ones.
800 for (int step = failure_step; step >= 0; --step) {
801 registration_steps[step].func(!reg, is_system);
802 }
803 }
804
805 return hr;
806}
807
808} // namespace
809
810// DLL Entry Point
811extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
812 DWORD reason,
813 LPVOID reserved) {
814 UNREFERENCED_PARAMETER(instance);
815 if (reason == DLL_PROCESS_ATTACH) {
816#ifndef NDEBUG
817 // Silence traces from the ATL registrar to reduce the log noise.
818 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
819 ATLTRACESTATUS_DISABLED);
820#endif
821 InitGoogleUrl();
822
823 g_exit_manager = new base::AtExitManager();
824 CommandLine::Init(0, NULL);
825 InitializeCrashReporting();
826 logging::InitLogging(
827 NULL,
828 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
829 logging::LOCK_LOG_FILE,
830 logging::DELETE_OLD_LOG_FILE,
831 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
832
833 DllRedirector* dll_redirector = DllRedirector::GetInstance();
834 DCHECK(dll_redirector);
835
836 if (!dll_redirector->RegisterAsFirstCFModule()) {
837 // Someone else was here first, try and get a pointer to their
838 // DllGetClassObject export:
839 g_dll_get_class_object_redir_ptr =
840 dll_redirector->GetDllGetClassObjectPtr();
841 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
842 << "Found CF module with no DllGetClassObject export.";
843 }
844
845 // Enable ETW logging.
846 logging::LogEventProvider::Initialize(kChromeFrameProvider);
847 } else if (reason == DLL_PROCESS_DETACH) {
848 DllRedirector* dll_redirector = DllRedirector::GetInstance();
849 DCHECK(dll_redirector);
850
851 dll_redirector->UnregisterAsFirstCFModule();
852 g_patch_helper.UnpatchIfNeeded();
853 delete g_exit_manager;
854 g_exit_manager = NULL;
855 ShutdownCrashReporting();
856 }
857 return _AtlModule.DllMain(reason, reserved);
858}
859
860// Used to determine whether the DLL can be unloaded by OLE
861STDAPI DllCanUnloadNow() {
862 return _AtlModule.DllCanUnloadNow();
863}
864
865// Returns a class factory to create an object of the requested type
866STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
867 // If we found another module present when we were loaded, then delegate to
868 // that:
869 if (g_dll_get_class_object_redir_ptr) {
870 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
871 }
872
873 // Enable sniffing and switching only if asked for BHO
874 // (we use BHO to get loaded in IE).
875 if (rclsid == CLSID_ChromeFrameBHO) {
876 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
877 }
878
879 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
880}
881
882// DllRegisterServer - Adds entries to the system registry
883STDAPI DllRegisterServer() {
884 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
885 BHO_CLSID | BHO_REGISTRATION;
886
887 HRESULT hr = CustomRegistration(flags, true, true);
888 if (SUCCEEDED(hr)) {
889 SetupRunOnce();
890 }
891
892 return hr;
893}
894
895// DllUnregisterServer - Removes entries from the system registry
896STDAPI DllUnregisterServer() {
897 HRESULT hr = CustomRegistration(ALL, false, true);
898 return hr;
899}
900
901// DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
902STDAPI DllRegisterUserServer() {
903 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
904 BHO_CLSID | BHO_REGISTRATION;
905
906 HRESULT hr = CustomRegistration(flags, TRUE, false);
907 if (SUCCEEDED(hr)) {
908 SetupRunOnce();
909 }
910
911 return hr;
912}
913
914// DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
915STDAPI DllUnregisterUserServer() {
916 HRESULT hr = CustomRegistration(ALL, FALSE, false);
917 return hr;
918}
919
920// Object entries go here instead of with each object, so that we can move
921// the objects to a lib. Also reduces magic.
922OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
923OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
924OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
925OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)