blob: 7b80394fcf29a0984df7ae6c825b3952b47a0008 [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>
11
[email protected]f7817822009-09-24 05:11:5812#include "base/at_exit.h"
13#include "base/command_line.h"
14#include "base/file_util.h"
15#include "base/file_version_info.h"
16#include "base/logging.h"
[email protected]5ee34132009-11-25 21:32:2617#include "base/logging_win.h"
[email protected]f7817822009-09-24 05:11:5818#include "base/path_service.h"
[email protected]c9c077792010-08-03 14:39:4219#include "base/string_number_conversions.h"
[email protected]f7817822009-09-24 05:11:5820#include "base/string_piece.h"
21#include "base/string_util.h"
22#include "base/sys_string_conversions.h"
[email protected]2d6503982010-10-17 04:41:5423#include "base/win/registry.h"
[email protected]935aa542010-10-15 01:59:1524#include "base/win/windows_version.h"
[email protected]f7817822009-09-24 05:11:5825#include "chrome/common/chrome_constants.h"
[email protected]02ea78a2010-07-15 16:52:2826#include "chrome/common/chrome_switches.h"
27#include "chrome/installer/util/google_update_settings.h"
[email protected]f7817822009-09-24 05:11:5828#include "chrome_frame/bho.h"
[email protected]ea9ed97d2010-01-05 19:16:2329#include "chrome_frame/chrome_active_document.h"
30#include "chrome_frame/chrome_frame_activex.h"
[email protected]f7817822009-09-24 05:11:5831#include "chrome_frame/chrome_frame_automation.h"
[email protected]53556e12009-10-15 21:49:2232#include "chrome_frame/chrome_frame_reporting.h"
[email protected]79b663c2010-05-28 17:27:1733#include "chrome_frame/chrome_launcher_utils.h"
[email protected]ea9ed97d2010-01-05 19:16:2334#include "chrome_frame/chrome_protocol.h"
[email protected]c6352e92010-12-03 01:57:4735#include "chrome_frame/dll_redirector.h"
36#include "chrome_frame/exception_barrier.h"
[email protected]f7817822009-09-24 05:11:5837#include "chrome_frame/resource.h"
38#include "chrome_frame/utils.h"
[email protected]cebd4132010-03-25 15:34:2239#include "googleurl/src/url_util.h"
[email protected]c6352e92010-12-03 01:57:4740#include "grit/chrome_frame_resources.h"
[email protected]cebd4132010-03-25 15:34:2241
[email protected]2d6503982010-10-17 04:41:5442using base::win::RegKey;
43
[email protected]cebd4132010-03-25 15:34:2244namespace {
45// This function has the side effect of initializing an unprotected
46// vector pointer inside GoogleUrl. If this is called during DLL loading,
[email protected]59b34a72010-09-01 17:30:3547// it has the effect of avoiding an initialization race on that pointer.
[email protected]cebd4132010-03-25 15:34:2248// TODO(siggi): fix GoogleUrl.
49void InitGoogleUrl() {
50 static const char kDummyUrl[] = "http://www.google.com";
51
52 url_util::IsStandard(kDummyUrl,
53 url_parse::MakeRange(0, arraysize(kDummyUrl)));
54}
[email protected]f7817822009-09-24 05:11:5855
[email protected]357219de2009-10-06 23:40:2256const wchar_t kInternetSettings[] =
57 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
58
[email protected]552fb6012010-02-03 17:24:2959const wchar_t kProtocolHandlers[] =
60 L"Software\\Classes\\Protocols\\Handler";
61
[email protected]02ea78a2010-07-15 16:52:2862const wchar_t kRunOnce[] =
63 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
64
[email protected]c5c6c8c2010-09-07 13:57:2165const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
66
67const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
[email protected]6a7748e2011-05-27 16:44:3168const wchar_t kChromeFrameHelperStartupArg[] = L"--startup";
[email protected]c5c6c8c2010-09-07 13:57:2169
70// Window class and window names.
71// TODO(robertshield): These and other constants need to be refactored into
72// a common chrome_frame_constants.h|cc and built into a separate lib
73// (either chrome_frame_utils or make another one).
74const wchar_t kChromeFrameHelperWindowClassName[] =
75 L"ChromeFrameHelperWindowClass";
76const wchar_t kChromeFrameHelperWindowName[] =
77 L"ChromeFrameHelperWindowName";
[email protected]f7817822009-09-24 05:11:5878
[email protected]5ee34132009-11-25 21:32:2679// {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
80static const GUID kChromeFrameProvider =
81 { 0x562bfc3, 0x2550, 0x45b4,
82 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
83
[email protected]9f7b8602011-09-08 19:45:4584const wchar_t kPostPlatformUAKey[] =
85 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
86 L"User Agent\\Post Platform";
87const wchar_t kChromeFramePrefix[] = L"chromeframe/";
[email protected]8adbf7e52010-04-14 20:03:2388
89// See comments in DllGetClassObject.
[email protected]52749842010-05-07 21:34:4190LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
[email protected]8adbf7e52010-04-14 20:03:2391
[email protected]6bdc0c02010-07-20 14:52:1392class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
[email protected]f7817822009-09-24 05:11:5893 public:
[email protected]6bdc0c02010-07-20 14:52:1394 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
[email protected]f7817822009-09-24 05:11:5895
[email protected]59b34a72010-09-01 17:30:3596 ChromeTabModule() : do_system_registration_(true) {}
97
[email protected]f7817822009-09-24 05:11:5898 DECLARE_LIBID(LIBID_ChromeTabLib)
99 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
100 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
101
102 // Override to add our SYSTIME binary value to registry scripts.
103 // See chrome_frame_activex.rgs for usage.
104 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
105 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
106
107 if (SUCCEEDED(hr)) {
108 SYSTEMTIME local_time;
109 ::GetSystemTime(&local_time);
[email protected]c9c077792010-08-03 14:39:42110 std::string hex(base::HexEncode(&local_time, sizeof(local_time)));
[email protected]f7817822009-09-24 05:11:58111 base::StringPiece sp_hex(hex);
112 hr = registrar->AddReplacement(L"SYSTIME",
113 base::SysNativeMBToWide(sp_hex).c_str());
114 DCHECK(SUCCEEDED(hr));
115 }
116
117 if (SUCCEEDED(hr)) {
[email protected]66ff7352009-10-15 05:09:50118 FilePath app_path =
119 chrome_launcher::GetChromeExecutablePath().DirName();
120 hr = registrar->AddReplacement(L"CHROME_APPPATH",
121 app_path.value().c_str());
[email protected]f7817822009-09-24 05:11:58122 DCHECK(SUCCEEDED(hr));
123 }
124
125 if (SUCCEEDED(hr)) {
126 hr = registrar->AddReplacement(L"CHROME_APPNAME",
127 chrome::kBrowserProcessExecutableName);
128 DCHECK(SUCCEEDED(hr));
129
130 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
131 scoped_ptr<FileVersionInfo> module_version_info(
132 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
133 DCHECK(module_version_info != NULL);
134 std::wstring file_version(module_version_info->file_version());
135 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
136 DCHECK(SUCCEEDED(hr));
137 }
138
139 if (SUCCEEDED(hr)) {
140 // Add the directory of chrome_launcher.exe. This will be the same
141 // as the directory for the current DLL.
142 std::wstring module_dir;
143 FilePath module_path;
144 if (PathService::Get(base::FILE_MODULE, &module_path)) {
[email protected]466a9222010-06-08 01:03:16145 module_dir = module_path.DirName().value();
[email protected]f7817822009-09-24 05:11:58146 } else {
147 NOTREACHED();
148 }
149 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
150 module_dir.c_str());
151 DCHECK(SUCCEEDED(hr));
152 }
153
154 if (SUCCEEDED(hr)) {
155 // Add the filename of chrome_launcher.exe
156 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
157 chrome_launcher::kLauncherExeBaseName);
158 DCHECK(SUCCEEDED(hr));
159 }
160
[email protected]59b34a72010-09-01 17:30:35161 if (SUCCEEDED(hr)) {
162 // Add the registry hive to use.
163 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
164 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
165 // few components that are registered by calling their
166 // static T::UpdateRegistry() methods directly, which doesn't allow
167 // pMapEntries to be passed through :-(
168 if (do_system_registration_) {
169 hr = registrar->AddReplacement(L"HIVE", L"HKLM");
170 } else {
171 hr = registrar->AddReplacement(L"HIVE", L"HKCU");
172 }
173 DCHECK(SUCCEEDED(hr));
174 }
175
[email protected]f7817822009-09-24 05:11:58176 return hr;
177 }
[email protected]59b34a72010-09-01 17:30:35178
179 // See comments in AddCommonRGSReplacements
180 bool do_system_registration_;
[email protected]f7817822009-09-24 05:11:58181};
182
183ChromeTabModule _AtlModule;
184
185base::AtExitManager* g_exit_manager = NULL;
[email protected]f7817822009-09-24 05:11:58186
[email protected]f7817822009-09-24 05:11:58187
[email protected]f7817822009-09-24 05:11:58188HRESULT RefreshElevationPolicy() {
189 const wchar_t kIEFrameDll[] = L"ieframe.dll";
190 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
191 HRESULT hr = E_NOTIMPL;
[email protected]1f08d682010-05-19 18:48:31192
193 // Stick an SEH in the chain to prevent the VEH from picking up on first
194 // chance exceptions caused by loading ieframe.dll. Use the vanilla
195 // ExceptionBarrier to report any exceptions that do make their way to us
196 // though.
197 ExceptionBarrier barrier;
198
[email protected]f7817822009-09-24 05:11:58199 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
200 if (ieframe_module) {
201 typedef HRESULT (__stdcall *IERefreshPolicy)();
202 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
203 GetProcAddress(ieframe_module, kIERefreshPolicy));
204
205 if (ie_refresh_policy) {
206 hr = ie_refresh_policy();
207 } else {
208 hr = HRESULT_FROM_WIN32(GetLastError());
209 }
[email protected]357219de2009-10-06 23:40:22210
[email protected]f7817822009-09-24 05:11:58211 FreeLibrary(ieframe_module);
212 } else {
213 hr = HRESULT_FROM_WIN32(GetLastError());
214 }
215
216 return hr;
217}
218
[email protected]02ea78a2010-07-15 16:52:28219// Experimental boot prefetch optimization for Chrome Frame
220//
221// If chrome is warmed up during a single reboot, it gets paged
222// in for subsequent reboots and the cold startup times essentially
223// look like warm times thereafter! The 'warm up' is done by
224// setting up a 'RunOnce' key during DLLRegisterServer of
225// npchrome_frame.dll.
226//
227// This works because chrome prefetch becomes part of boot
228// prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
229// reboots. As long as the sytem does not undergo significant
230// memory pressure those pages remain in memory and we get pretty
231// amazing startup times, down to about 300 ms from 1200 ms
232//
233// The downside is:
234// - Whether chrome frame is used or not, there's a read penalty
235// (1200-300 =) 900 ms for every boot.
236// - Heavy system memory usage after reboot will nullify the benefits
237// but the user will still pay the cost.
238// - Overall the time saved will always be less than total time spent
239// paging in chrome
240// - We are not sure when the chrome 'warm up' will age out from the
241// boot prefetch file.
242//
243// The idea here is to try this out on chrome frame dev channel
244// and see if it produces a significant drift in startup numbers.
245HRESULT SetupRunOnce() {
[email protected]7fc3e6922010-11-18 17:56:54246 HRESULT result = E_FAIL;
[email protected]02ea78a2010-07-15 16:52:28247
248 std::wstring channel_name;
[email protected]7fc3e6922010-11-18 17:56:54249 if (base::win::GetVersion() < base::win::VERSION_VISTA &&
[email protected]3e76e27b2011-05-02 21:19:01250 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name)) {
[email protected]7fc3e6922010-11-18 17:56:54251 std::transform(channel_name.begin(), channel_name.end(),
252 channel_name.begin(), tolower);
253 // Use this only for the dev channel and CEEE channels.
254 if (channel_name.find(L"dev") != std::wstring::npos ||
255 channel_name.find(L"ceee") != std::wstring::npos) {
[email protected]7fc3e6922010-11-18 17:56:54256 HKEY hive = HKEY_CURRENT_USER;
257 if (IsSystemProcess()) {
258 // For system installs, our updates will be running as SYSTEM which
259 // makes writing to a RunOnce key under HKCU not so terribly useful.
260 hive = HKEY_LOCAL_MACHINE;
261 }
[email protected]74ecb5a42010-09-03 00:44:35262
[email protected]7fc3e6922010-11-18 17:56:54263 RegKey run_once;
[email protected]e06f4d52011-01-19 07:28:46264 LONG ret = run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE);
265 if (ret == ERROR_SUCCESS) {
[email protected]7fc3e6922010-11-18 17:56:54266 CommandLine run_once_cmd(chrome_launcher::GetChromeExecutablePath());
267 run_once_cmd.AppendSwitchASCII(switches::kAutomationClientChannelID,
[email protected]05076ba22010-07-30 05:59:57268 "0");
[email protected]7fc3e6922010-11-18 17:56:54269 run_once_cmd.AppendSwitch(switches::kChromeFrame);
[email protected]e06f4d52011-01-19 07:28:46270 ret = run_once.WriteValue(L"A",
[email protected]61a4c6f2011-07-20 04:54:52271 run_once_cmd.GetCommandLineString().c_str());
[email protected]7fc3e6922010-11-18 17:56:54272 }
[email protected]e06f4d52011-01-19 07:28:46273 result = HRESULT_FROM_WIN32(ret);
[email protected]7fc3e6922010-11-18 17:56:54274 } else {
275 result = S_FALSE;
276 }
277 } else {
278 // We're on a non-XP version of Windows or on a stable channel. Nothing
279 // needs doing.
280 result = S_FALSE;
[email protected]552fb6012010-02-03 17:24:29281 }
282
[email protected]7fc3e6922010-11-18 17:56:54283 return result;
[email protected]552fb6012010-02-03 17:24:29284}
285
[email protected]c5c6c8c2010-09-07 13:57:21286// Helper method called for user-level installs where we don't have admin
287// permissions. Starts up the long running process and registers it to get it
288// started at next boot.
[email protected]9f7b8602011-09-08 19:45:45289HRESULT SetupUserLevelHelper() {
290 HRESULT hr = S_OK;
291
[email protected]c5c6c8c2010-09-07 13:57:21292 // Remove existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50293 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21294
295 // Build the chrome_frame_helper command line.
296 FilePath module_path;
297 FilePath helper_path;
298 if (PathService::Get(base::FILE_MODULE, &module_path)) {
299 module_path = module_path.DirName();
300 helper_path = module_path.Append(kChromeFrameHelperExe);
301 if (!file_util::PathExists(helper_path)) {
302 // If we can't find the helper in the current directory, try looking
303 // one up (this is the layout in the build output folder).
304 module_path = module_path.DirName();
305 helper_path = module_path.Append(kChromeFrameHelperExe);
306 DCHECK(file_util::PathExists(helper_path)) <<
307 "Could not find chrome_frame_helper.exe.";
308 }
[email protected]9f7b8602011-09-08 19:45:45309
310 // Find window handle of existing instance.
311 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
312 kChromeFrameHelperWindowName);
313
314 if (file_util::PathExists(helper_path)) {
315 std::wstring helper_path_cmd(L"\"");
316 helper_path_cmd += helper_path.value();
317 helper_path_cmd += L"\" ";
318 helper_path_cmd += kChromeFrameHelperStartupArg;
319
320 // Add new run-at-startup entry.
321 if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
322 helper_path_cmd)) {
323 hr = E_FAIL;
324 LOG(ERROR) << "Could not add helper process to auto run key.";
325 }
326
327 // Start new instance.
328 base::LaunchOptions options;
329 options.start_hidden = true;
330 bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
331 if (!launched) {
332 hr = E_FAIL;
333 PLOG(DFATAL) << "Could not launch helper process.";
334 }
335
336 // Kill old instance using window handle.
337 if (IsWindow(old_window)) {
338 BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
339 if (!result) {
340 PLOG(ERROR) << "Failed to post close message to old helper process: ";
341 }
342 }
343 } else {
344 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
345 }
[email protected]c5c6c8c2010-09-07 13:57:21346 } else {
[email protected]9f7b8602011-09-08 19:45:45347 hr = E_UNEXPECTED;
[email protected]c5c6c8c2010-09-07 13:57:21348 NOTREACHED();
349 }
350
[email protected]9f7b8602011-09-08 19:45:45351 return hr;
[email protected]c5c6c8c2010-09-07 13:57:21352}
353
[email protected]6a8515e42010-12-16 19:38:52354// To delete the user agent, set value to NULL.
355// The is_system parameter indicates whether this is a per machine or a per
356// user installation.
357HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
358 HRESULT hr = E_FAIL;
359 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
360
361 RegKey ua_key;
[email protected]9f7b8602011-09-08 19:45:45362 LONG reg_result = ua_key.Create(parent_hive, kPostPlatformUAKey,
363 KEY_READ | KEY_WRITE);
364 if (reg_result == ERROR_SUCCESS) {
[email protected]45b716b2011-01-14 18:43:53365 // Make sure that we unregister ChromeFrame UA strings registered previously
[email protected]9b7baa962011-01-14 20:07:07366 wchar_t value_name[MAX_PATH + 1] = {};
367 wchar_t value_data[MAX_PATH + 1] = {};
[email protected]45b716b2011-01-14 18:43:53368
369 DWORD value_index = 0;
370 while (value_index < ua_key.ValueCount()) {
[email protected]9b7baa962011-01-14 20:07:07371 DWORD name_size = arraysize(value_name);
372 DWORD value_size = arraysize(value_data);
[email protected]45b716b2011-01-14 18:43:53373 DWORD type = 0;
[email protected]9b7baa962011-01-14 20:07:07374 LRESULT ret = ::RegEnumValue(ua_key.Handle(), value_index, value_name,
[email protected]45b716b2011-01-14 18:43:53375 &name_size, NULL, &type,
[email protected]9b7baa962011-01-14 20:07:07376 reinterpret_cast<BYTE*>(value_data),
[email protected]45b716b2011-01-14 18:43:53377 &value_size);
378 if (ret == ERROR_SUCCESS) {
[email protected]9b7baa962011-01-14 20:07:07379 if (StartsWith(value_name, kChromeFramePrefix, false)) {
380 ua_key.DeleteValue(value_name);
[email protected]45b716b2011-01-14 18:43:53381 } else {
382 ++value_index;
383 }
384 } else {
385 break;
386 }
387 }
388
[email protected]6a8515e42010-12-16 19:38:52389 std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
390 chrome_frame_ua_value_name += GetCurrentModuleVersion();
391 if (value) {
392 ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value);
[email protected]6a8515e42010-12-16 19:38:52393 }
394 hr = S_OK;
395 } else {
[email protected]9f7b8602011-09-08 19:45:45396 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey
397 << ", error code = " << reg_result;
398 hr = HRESULT_FROM_WIN32(reg_result);
[email protected]6a8515e42010-12-16 19:38:52399 }
400 return hr;
401}
402
[email protected]357219de2009-10-06 23:40:22403class SecurityDescBackup {
404 public:
405 explicit SecurityDescBackup(const std::wstring& backup_key)
406 : backup_key_name_(backup_key) {}
407 ~SecurityDescBackup() {}
408
409 // Save given security descriptor to the backup key.
410 bool SaveSecurity(const CSecurityDesc& sd) {
411 CString str;
412 if (!sd.ToString(&str))
413 return false;
414
415 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
416 KEY_READ | KEY_WRITE);
417 if (backup_key.Valid()) {
[email protected]e06f4d52011-01-19 07:28:46418 return backup_key.WriteValue(NULL, str.GetString()) == ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22419 }
420
421 return false;
422 }
423
424 // Restore security descriptor from backup key to given key name.
425 bool RestoreSecurity(const wchar_t* key_name) {
426 std::wstring sddl;
427 if (!ReadBackupKey(&sddl))
428 return false;
429
430 // Create security descriptor from string.
431 CSecurityDesc sd;
432 if (!sd.FromString(sddl.c_str()))
433 return false;
434
435 bool result = true;
436 // Restore DACL and Owner of the key from saved security descriptor.
437 CDacl dacl;
438 CSid owner;
439 sd.GetDacl(&dacl);
440 sd.GetOwner(&owner);
441
442 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
443 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
444 const_cast<SID*>(owner.GetPSID()), NULL,
445 const_cast<ACL*>(dacl.GetPACL()), NULL);
446
447 DeleteBackupKey();
448 return (error == ERROR_SUCCESS);
449 }
450
451 private:
452 // Read SDDL string from backup key
453 bool ReadBackupKey(std::wstring* sddl) {
454 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
455 if (!backup_key.Valid())
456 return false;
457
458 DWORD len = 0;
459 DWORD reg_type = REG_NONE;
[email protected]e06f4d52011-01-19 07:28:46460 if (backup_key.ReadValue(NULL, NULL, &len, &reg_type) != ERROR_SUCCESS)
[email protected]357219de2009-10-06 23:40:22461 return false;
462
463 if (reg_type != REG_SZ)
464 return false;
465
466 size_t wchar_count = 1 + len / sizeof(wchar_t);
[email protected]e06f4d52011-01-19 07:28:46467 if (backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
468 &reg_type) != ERROR_SUCCESS) {
[email protected]357219de2009-10-06 23:40:22469 return false;
470 }
471
472 return true;
473 }
474
475 void DeleteBackupKey() {
476 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
477 }
478
479 std::wstring backup_key_name_;
480};
481
482struct TokenWithPrivileges {
483 TokenWithPrivileges() {
484 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
485 token_.GetUser(&user_);
486 }
487
488 ~TokenWithPrivileges() {
489 token_.EnableDisablePrivileges(take_ownership_);
490 token_.EnableDisablePrivileges(restore_);
491 }
492
493 bool EnablePrivileges() {
494 if (take_ownership_.GetCount() == 0)
495 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
496 &take_ownership_))
497 return false;
498
499 if (restore_.GetCount() == 0)
500 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
501 return false;
502
503 return true;
504 }
505
506 const CSid& GetUser() const {
507 return user_;
508 }
509
510 private:
511 CAccessToken token_;
512 CTokenPrivileges take_ownership_;
513 CTokenPrivileges restore_;
514 CSid user_;
515};
516
[email protected]9f7b8602011-09-08 19:45:45517HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
[email protected]357219de2009-10-06 23:40:22518 std::wstring key_name = kInternetSettings;
519 key_name.append(L"\\Secure Mime Handlers");
[email protected]59b34a72010-09-01 17:30:35520 RegKey key(root_key, key_name.c_str(), KEY_READ | KEY_WRITE);
[email protected]357219de2009-10-06 23:40:22521 if (!key.Valid())
522 return false;
523
[email protected]e06f4d52011-01-19 07:28:46524 LONG result1 = ERROR_SUCCESS;
525 LONG result2 = ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22526 if (set) {
[email protected]e06f4d52011-01-19 07:28:46527 result1 = key.WriteValue(L"ChromeTab.ChromeActiveDocument", 1);
528 result2 = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1);
[email protected]357219de2009-10-06 23:40:22529 } else {
[email protected]e06f4d52011-01-19 07:28:46530 result1 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
531 result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1");
[email protected]357219de2009-10-06 23:40:22532 }
533
[email protected]9f7b8602011-09-08 19:45:45534 return result1 != ERROR_SUCCESS ? HRESULT_FROM_WIN32(result1) :
535 HRESULT_FROM_WIN32(result2);
[email protected]357219de2009-10-06 23:40:22536}
537
[email protected]9f7b8602011-09-08 19:45:45538// Chrome Frame registration functions.
539//-----------------------------------------------------------------------------
540HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
[email protected]59b34a72010-09-01 17:30:35541 if (!is_system) {
542 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
[email protected]935aa542010-10-15 01:59:15543 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
[email protected]59b34a72010-09-01 17:30:35544 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22545 }
546
547 std::wstring mime_key = kInternetSettings;
548 mime_key.append(L"\\Secure Mime Handlers");
549 std::wstring backup_key = kInternetSettings;
550 backup_key.append(L"\\__backup_SMH__");
551 std::wstring object_name = L"MACHINE\\";
552 object_name.append(mime_key);
553
554 TokenWithPrivileges token_;
555 if (!token_.EnablePrivileges())
[email protected]9f7b8602011-09-08 19:45:45556 return E_ACCESSDENIED;
[email protected]357219de2009-10-06 23:40:22557
558 // If there is a backup key - something bad happened; try to restore
559 // security on "Secure Mime Handlers" from the backup.
560 SecurityDescBackup backup(backup_key);
561 backup.RestoreSecurity(object_name.c_str());
562
563 // Read old security descriptor of the Mime key first.
564 CSecurityDesc sd;
565 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
[email protected]9f7b8602011-09-08 19:45:45566 return E_FAIL;
[email protected]357219de2009-10-06 23:40:22567 }
568
569 backup.SaveSecurity(sd);
[email protected]9f7b8602011-09-08 19:45:45570 HRESULT hr = E_FAIL;
[email protected]357219de2009-10-06 23:40:22571 // set new owner
572 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
573 // set new dacl
574 CDacl new_dacl;
575 sd.GetDacl(&new_dacl);
576 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
577 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
[email protected]9f7b8602011-09-08 19:45:45578 hr = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22579 }
580 }
581
582 backup.RestoreSecurity(object_name.c_str());
[email protected]9f7b8602011-09-08 19:45:45583 return hr;
[email protected]357219de2009-10-06 23:40:22584}
[email protected]9f7b8602011-09-08 19:45:45585
586HRESULT RegisterActiveDoc(bool reg, bool is_system) {
587 // We have to call the static T::UpdateRegistry function instead of
588 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg)
589 // because there is specific OLEMISC replacement.
590 return ChromeActiveDocument::UpdateRegistry(reg);
591}
592
593HRESULT RegisterActiveX(bool reg, bool is_system) {
594 // We have to call the static T::UpdateRegistry function instead of
595 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
596 // because there is specific OLEMISC replacement.
597 return ChromeFrameActivex::UpdateRegistry(reg);
598}
599
600HRESULT RegisterElevationPolicy(bool reg, bool is_system) {
601 HRESULT hr = S_OK;
602 if (reg && base::win::GetVersion() >= base::win::VERSION_VISTA) {
603 // Register the elevation policy. This must succeed for Chrome Frame to
604 // be able launch Chrome when running in low-integrity IE.
605 // Note that this is not done on unregistration, the installer will
606 // explicitly remove the policy on uninstall.
607 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION,
608 reg);
609 if (SUCCEEDED(hr)) {
610 hr = RefreshElevationPolicy();
611 }
612 }
613 return hr;
614}
615
616HRESULT RegisterProtocol(bool reg, bool is_system) {
617 return _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
618}
619
620HRESULT RegisterBhoClsid(bool reg, bool is_system) {
621 return Bho::UpdateRegistry(reg);
622}
623
624HRESULT RegisterBhoIE(bool reg, bool is_system) {
625 if (is_system) {
626 return _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
627 } else {
628 if (reg) {
629 // Setup the long running process:
630 return SetupUserLevelHelper();
631 } else {
632 // Unschedule the user-level helper. Note that we don't kill it here
633 // so that during updates we don't have a time window with no running
634 // helper. Uninstalls and updates will explicitly kill the helper from
635 // within the installer. Unregister existing run-at-startup entry.
636 return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER,
637 kRunKeyName) ? S_OK : E_FAIL;
638 }
639 }
640}
641
642HRESULT RegisterTypeLib(bool reg, bool is_system) {
643 if (reg && !is_system) {
644 // Enables the RegisterTypeLib Function function to override default
645 // registry mappings under Windows Vista Service Pack 1 (SP1),
646 // Windows Server 2008, and later operating system versions
647 typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
648 OaEnablePerUserTypeLibReg per_user_typelib_func =
649 reinterpret_cast<OaEnablePerUserTypeLibReg>(
650 GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
651 "OaEnablePerUserTLibRegistration"));
652 if (per_user_typelib_func) {
653 (*per_user_typelib_func)();
654 }
655 }
656 return reg ?
657 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
658 NULL, !is_system) :
659 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
660 NULL, !is_system);
661}
662
663HRESULT RegisterLegacyNPAPICleanup(bool reg, bool is_system) {
664 if (!reg) {
665 _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
666 UtilRemovePersistentNPAPIMarker();
667 }
668 // Ignore failures.
669 return S_OK;
670}
671
672HRESULT RegisterAppId(bool reg, bool is_system) {
673 return _AtlModule.UpdateRegistryAppId(reg);
674}
675
676HRESULT RegisterUserAgent(bool reg, bool is_system) {
677 if (reg) {
678 return SetChromeFrameUA(is_system, L"1");
679 } else {
680 return SetChromeFrameUA(is_system, NULL);
681 }
682}
683
684enum RegistrationStepId {
685 kStepSecuredMimeHandler = 0,
686 kStepActiveDoc = 1,
687 kStepActiveX = 2,
688 kStepElevationPolicy = 3,
689 kStepProtocol = 4,
690 kStepBhoClsid = 5,
691 kStepBhoRegistration = 6,
692 kStepRegisterTypeLib = 7,
693 kStepNpapiCleanup = 8,
694 kStepAppId = 9,
695 kStepUserAgent = 10,
696 kStepEnd = 11
697};
698
699enum RegistrationFlags {
700 ACTIVEX = 0x0001,
701 ACTIVEDOC = 0x0002,
702 GCF_PROTOCOL = 0x0004,
703 BHO_CLSID = 0x0008,
704 BHO_REGISTRATION = 0x0010,
705 TYPELIB = 0x0020,
706
707 ALL = 0xFFFF
708};
709
710// Mux the failure step into the hresult. We take only the first four bits
711// and stick those into the top four bits of the facility code. We also set the
712// Customer bit to be polite. Graphically, we write our error code to the
713// bits marked with ^:
714// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
715// 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
716// +---+-+-+-----------------------+-------------------------------+
717// |Sev|C|R| Facility | Code |
718// +---+-+-+-----------------------+-------------------------------+
719// ^ ^ ^ ^ ^
720// See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for
721// more details on HRESULTS.
722//
723// The resulting error can be extracted by:
724// error_code = (fiddled_hr & 0x07800000) >> 23
725HRESULT MuxErrorIntoHRESULT(HRESULT hr, int error_code) {
726 DCHECK_GE(error_code, 0);
727 DCHECK_LT(error_code, kStepEnd);
728 COMPILE_ASSERT(kStepEnd <= 0xF, update_error_muxing_too_many_steps);
729
730 // Check that our four desired bits are clear.
731 // 0xF87FFFFF == 11111000011111111111111111111111
732 DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr);
733
734 HRESULT fiddled_hr = ((error_code & 0xF) << 23) | hr;
735 fiddled_hr |= 1 << 29; // Set the customer bit.
736
737 return fiddled_hr;
738}
739
740HRESULT CustomRegistration(uint16 reg_flags, bool reg, bool is_system) {
741 if (reg && (reg_flags & (ACTIVEDOC | ACTIVEX)))
742 reg_flags |= (TYPELIB | GCF_PROTOCOL);
743
744 // Set the flag that gets checked in AddCommonRGSReplacements before doing
745 // registration work.
746 _AtlModule.do_system_registration_ = is_system;
747
748 typedef HRESULT (*RegistrationFn)(bool reg, bool is_system);
749 struct RegistrationStep {
750 RegistrationStepId id;
751 uint16 condition;
752 RegistrationFn func;
753 };
754 static const RegistrationStep registration_steps[] = {
755 { kStepSecuredMimeHandler, ACTIVEDOC, &RegisterSecuredMimeHandler },
756 { kStepActiveDoc, ACTIVEDOC, &RegisterActiveDoc },
757 { kStepActiveX, ACTIVEX, &RegisterActiveX },
758 { kStepElevationPolicy, (ACTIVEDOC | ACTIVEX), &RegisterElevationPolicy },
759 { kStepProtocol, GCF_PROTOCOL, &RegisterProtocol },
760 { kStepBhoClsid, BHO_CLSID, &RegisterBhoClsid },
761 { kStepBhoRegistration, BHO_REGISTRATION, &RegisterBhoIE },
762 { kStepRegisterTypeLib, TYPELIB, &RegisterTypeLib },
763 { kStepNpapiCleanup, ALL, &RegisterLegacyNPAPICleanup },
764 { kStepAppId, ALL, &RegisterAppId },
765 { kStepUserAgent, ALL, &RegisterUserAgent }
766 };
767
768 HRESULT hr = S_OK;
769
770 bool rollback = false;
771 int failure_step = 0;
772 HRESULT step_hr = S_OK;
773 for (int step = 0; step < arraysize(registration_steps); ++step) {
774 if ((reg_flags & registration_steps[step].condition) != 0) {
775 step_hr = registration_steps[step].func(reg, is_system);
776 if (FAILED(step_hr)) {
777 // Store only the first failing HRESULT with the step value muxed in.
778 if (hr == S_OK) {
779 hr = MuxErrorIntoHRESULT(step_hr, step);
780 }
781
782 // On registration if a step fails, we abort and rollback.
783 if (reg) {
784 rollback = true;
785 failure_step = step;
786 break;
787 }
788 }
789 }
790 }
791
792 if (rollback) {
793 DCHECK(reg);
794 // Rollback the failing action and all preceding ones.
795 for (int step = failure_step; step >= 0; --step) {
796 registration_steps[step].func(!reg, is_system);
797 }
798 }
799
800 return hr;
801}
802
803} // namespace
804
805// DLL Entry Point
806extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
807 DWORD reason,
808 LPVOID reserved) {
809 UNREFERENCED_PARAMETER(instance);
810 if (reason == DLL_PROCESS_ATTACH) {
811#ifndef NDEBUG
812 // Silence traces from the ATL registrar to reduce the log noise.
813 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
814 ATLTRACESTATUS_DISABLED);
815#endif
816 InitGoogleUrl();
817
818 g_exit_manager = new base::AtExitManager();
819 CommandLine::Init(0, NULL);
820 InitializeCrashReporting();
821 logging::InitLogging(
822 NULL,
823 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
824 logging::LOCK_LOG_FILE,
825 logging::DELETE_OLD_LOG_FILE,
826 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
827
828 DllRedirector* dll_redirector = DllRedirector::GetInstance();
829 DCHECK(dll_redirector);
830
831 if (!dll_redirector->RegisterAsFirstCFModule()) {
832 // Someone else was here first, try and get a pointer to their
833 // DllGetClassObject export:
834 g_dll_get_class_object_redir_ptr =
835 dll_redirector->GetDllGetClassObjectPtr();
836 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
837 << "Found CF module with no DllGetClassObject export.";
838 }
839
840 // Enable ETW logging.
841 logging::LogEventProvider::Initialize(kChromeFrameProvider);
842 } else if (reason == DLL_PROCESS_DETACH) {
843 DllRedirector* dll_redirector = DllRedirector::GetInstance();
844 DCHECK(dll_redirector);
845
846 dll_redirector->UnregisterAsFirstCFModule();
847 g_patch_helper.UnpatchIfNeeded();
848 delete g_exit_manager;
849 g_exit_manager = NULL;
850 ShutdownCrashReporting();
851 }
852 return _AtlModule.DllMain(reason, reserved);
853}
854
855// Used to determine whether the DLL can be unloaded by OLE
856STDAPI DllCanUnloadNow() {
857 return _AtlModule.DllCanUnloadNow();
858}
859
860// Returns a class factory to create an object of the requested type
861STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
862 // If we found another module present when we were loaded, then delegate to
863 // that:
864 if (g_dll_get_class_object_redir_ptr) {
865 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
866 }
867
868 // Enable sniffing and switching only if asked for BHO
869 // (we use BHO to get loaded in IE).
870 if (rclsid == CLSID_ChromeFrameBHO) {
871 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
872 }
873
874 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
875}
876
877// DllRegisterServer - Adds entries to the system registry
878STDAPI DllRegisterServer() {
879 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
880 BHO_CLSID | BHO_REGISTRATION;
881
882 HRESULT hr = CustomRegistration(flags, true, true);
883 if (SUCCEEDED(hr)) {
884 SetupRunOnce();
885 }
886
887 return hr;
888}
889
890// DllUnregisterServer - Removes entries from the system registry
891STDAPI DllUnregisterServer() {
892 HRESULT hr = CustomRegistration(ALL, false, true);
893 return hr;
894}
895
896// DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
897STDAPI DllRegisterUserServer() {
898 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
899 BHO_CLSID | BHO_REGISTRATION;
900
901 HRESULT hr = CustomRegistration(flags, TRUE, false);
902 if (SUCCEEDED(hr)) {
903 SetupRunOnce();
904 }
905
906 return hr;
907}
908
909// DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
910STDAPI DllUnregisterUserServer() {
911 HRESULT hr = CustomRegistration(ALL, FALSE, false);
912 return hr;
913}
914
915// Object entries go here instead of with each object, so that we can move
916// the objects to a lib. Also reduces magic.
917OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
918OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
919OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
920OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)