[Telemetry]: Add Browsermark 2.0 benchmark suite.
[chromium-blink-merge.git] / chrome_frame / chrome_tab.cc
blobb3c209985600a4f9c8381bb06b1f5084275525c5
1 // Copyright (c) 2012 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 // chrome_tab.cc : Implementation of DLL Exports.
7 // Need to include this before the ATL headers below.
8 #include "chrome_frame/chrome_tab.h"
10 #include <atlsecurity.h>
11 #include <objbase.h>
13 #include "base/at_exit.h"
14 #include "base/basictypes.h"
15 #include "base/command_line.h"
16 #include "base/file_util.h"
17 #include "base/file_version_info.h"
18 #include "base/logging.h"
19 #include "base/logging_win.h"
20 #include "base/path_service.h"
21 #include "base/process/launch.h"
22 #include "base/strings/string16.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_piece.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/sys_string_conversions.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/win/registry.h"
29 #include "base/win/windows_version.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/installer/util/google_update_settings.h"
33 #include "chrome_frame/bho.h"
34 #include "chrome_frame/chrome_active_document.h"
35 #include "chrome_frame/chrome_frame_activex.h"
36 #include "chrome_frame/chrome_frame_automation.h"
37 #include "chrome_frame/chrome_frame_reporting.h"
38 #include "chrome_frame/chrome_launcher_utils.h"
39 #include "chrome_frame/chrome_protocol.h"
40 #include "chrome_frame/dll_redirector.h"
41 #include "chrome_frame/exception_barrier.h"
42 #include "chrome_frame/pin_module.h"
43 #include "chrome_frame/resource.h"
44 #include "chrome_frame/utils.h"
45 #include "components/variations/entropy_provider.h"
46 #include "grit/chrome_frame_resources.h"
47 #include "url/url_util.h"
49 #if _ATL_VER >= 0x0C00
50 // This was removed between the VS2010 version and the VS2013 version, and
51 // the unsuffixed version was repurposed to mean 'S'.
52 #define UpdateRegistryFromResourceS UpdateRegistryFromResource
53 #endif
55 using base::win::RegKey;
57 namespace {
59 const wchar_t kInternetSettings[] =
60 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
62 const wchar_t kProtocolHandlers[] =
63 L"Software\\Classes\\Protocols\\Handler";
65 const wchar_t kRunOnce[] =
66 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
68 const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
70 const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
71 const wchar_t kChromeFrameHelperStartupArg[] = L"--startup";
73 // Window class and window names.
74 // TODO(robertshield): These and other constants need to be refactored into
75 // a common chrome_frame_constants.h|cc and built into a separate lib
76 // (either chrome_frame_utils or make another one).
77 const wchar_t kChromeFrameHelperWindowClassName[] =
78 L"ChromeFrameHelperWindowClass";
79 const wchar_t kChromeFrameHelperWindowName[] =
80 L"ChromeFrameHelperWindowName";
82 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
83 const GUID kChromeFrameProvider =
84 { 0x562bfc3, 0x2550, 0x45b4,
85 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
87 const wchar_t kPostPlatformUAKey[] =
88 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
89 L"User Agent\\Post Platform";
90 const wchar_t kChromeFramePrefix[] = L"chromeframe/";
92 // See comments in DllGetClassObject.
93 LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
95 // This function has the side effect of initializing an unprotected
96 // vector pointer inside GoogleUrl. If this is called during DLL loading,
97 // it has the effect of avoiding an initialization race on that pointer.
98 // TODO(siggi): fix GoogleUrl.
99 void InitGoogleUrl() {
100 static const char kDummyUrl[] = "http://www.google.com";
102 url_util::IsStandard(kDummyUrl,
103 url_parse::MakeRange(0, arraysize(kDummyUrl)));
106 class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
107 public:
108 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
110 ChromeTabModule() : do_system_registration_(true), crash_reporting_(NULL) {}
112 DECLARE_LIBID(LIBID_ChromeTabLib)
113 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
114 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
116 // Override to add our SYSTIME binary value to registry scripts.
117 // See chrome_frame_activex.rgs for usage.
118 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
119 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
121 if (SUCCEEDED(hr)) {
122 SYSTEMTIME local_time;
123 ::GetSystemTime(&local_time);
124 std::string hex(base::HexEncode(&local_time, sizeof(local_time)));
125 base::StringPiece sp_hex(hex);
126 hr = registrar->AddReplacement(L"SYSTIME",
127 base::SysNativeMBToWide(sp_hex).c_str());
128 DCHECK(SUCCEEDED(hr));
131 if (SUCCEEDED(hr)) {
132 base::FilePath app_path =
133 chrome_launcher::GetChromeExecutablePath().DirName();
134 hr = registrar->AddReplacement(L"CHROME_APPPATH",
135 app_path.value().c_str());
136 DCHECK(SUCCEEDED(hr));
139 if (SUCCEEDED(hr)) {
140 hr = registrar->AddReplacement(L"CHROME_APPNAME",
141 chrome::kBrowserProcessExecutableName);
142 DCHECK(SUCCEEDED(hr));
144 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
145 scoped_ptr<FileVersionInfo> module_version_info(
146 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
147 DCHECK(module_version_info != NULL);
148 std::wstring file_version(module_version_info->file_version());
149 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
150 DCHECK(SUCCEEDED(hr));
153 if (SUCCEEDED(hr)) {
154 // Add the directory of chrome_launcher.exe. This will be the same
155 // as the directory for the current DLL.
156 std::wstring module_dir;
157 base::FilePath module_path;
158 if (PathService::Get(base::FILE_MODULE, &module_path)) {
159 module_dir = module_path.DirName().value();
160 } else {
161 NOTREACHED();
163 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
164 module_dir.c_str());
165 DCHECK(SUCCEEDED(hr));
168 if (SUCCEEDED(hr)) {
169 // Add the filename of chrome_launcher.exe
170 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
171 chrome_launcher::kLauncherExeBaseName);
172 DCHECK(SUCCEEDED(hr));
175 if (SUCCEEDED(hr)) {
176 // Add the registry hive to use.
177 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
178 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
179 // few components that are registered by calling their
180 // static T::UpdateRegistry() methods directly, which doesn't allow
181 // pMapEntries to be passed through :-(
182 if (do_system_registration_) {
183 hr = registrar->AddReplacement(L"HIVE", L"HKLM");
184 } else {
185 hr = registrar->AddReplacement(L"HIVE", L"HKCU");
187 DCHECK(SUCCEEDED(hr));
190 if (SUCCEEDED(hr)) {
191 // Add the Chrome Frame CLSID.
192 wchar_t cf_clsid[64];
193 StringFromGUID2(CLSID_ChromeFrame, &cf_clsid[0], arraysize(cf_clsid));
194 hr = registrar->AddReplacement(L"CHROME_FRAME_CLSID", &cf_clsid[0]);
197 return hr;
200 // The module is "locked" when an object takes a reference on it. The first
201 // time it is locked, take a reference on crash reporting to bind its lifetime
202 // to the module.
203 virtual LONG Lock() throw() {
204 LONG result = ParentClass::Lock();
205 if (result == 1) {
206 DCHECK_EQ(crash_reporting_,
207 static_cast<chrome_frame::ScopedCrashReporting*>(NULL));
208 crash_reporting_ = new chrome_frame::ScopedCrashReporting();
210 return result;
213 // The module is "unlocked" when an object that had a reference on it is
214 // destroyed. The last time it is unlocked, release the reference on crash
215 // reporting.
216 virtual LONG Unlock() throw() {
217 LONG result = ParentClass::Unlock();
218 if (!result) {
219 DCHECK_NE(crash_reporting_,
220 static_cast<chrome_frame::ScopedCrashReporting*>(NULL));
221 delete crash_reporting_;
222 crash_reporting_ = NULL;
224 return result;
227 // See comments in AddCommonRGSReplacements
228 bool do_system_registration_;
230 private:
231 // A scoper created when the module is initially locked and destroyed when it
232 // is finally unlocked. This is not a scoped_ptr since that could cause
233 // reporting to shut down at exit, which would lead to problems with the
234 // loader lock.
235 chrome_frame::ScopedCrashReporting* crash_reporting_;
238 ChromeTabModule _AtlModule;
240 base::AtExitManager* g_exit_manager = NULL;
242 HRESULT RefreshElevationPolicy() {
243 const wchar_t kIEFrameDll[] = L"ieframe.dll";
244 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
245 HRESULT hr = E_NOTIMPL;
247 // Stick an SEH in the chain to prevent the VEH from picking up on first
248 // chance exceptions caused by loading ieframe.dll. Use the vanilla
249 // ExceptionBarrier to report any exceptions that do make their way to us
250 // though.
251 ExceptionBarrier barrier;
253 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
254 if (ieframe_module) {
255 typedef HRESULT (__stdcall *IERefreshPolicy)();
256 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
257 GetProcAddress(ieframe_module, kIERefreshPolicy));
259 if (ie_refresh_policy) {
260 hr = ie_refresh_policy();
261 } else {
262 hr = HRESULT_FROM_WIN32(GetLastError());
265 FreeLibrary(ieframe_module);
266 } else {
267 hr = HRESULT_FROM_WIN32(GetLastError());
270 return hr;
273 // Experimental boot prefetch optimization for Chrome Frame
275 // If chrome is warmed up during a single reboot, it gets paged
276 // in for subsequent reboots and the cold startup times essentially
277 // look like warm times thereafter! The 'warm up' is done by
278 // setting up a 'RunOnce' key during DLLRegisterServer of
279 // npchrome_frame.dll.
281 // This works because chrome prefetch becomes part of boot
282 // prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
283 // reboots. As long as the sytem does not undergo significant
284 // memory pressure those pages remain in memory and we get pretty
285 // amazing startup times, down to about 300 ms from 1200 ms
287 // The downside is:
288 // - Whether chrome frame is used or not, there's a read penalty
289 // (1200-300 =) 900 ms for every boot.
290 // - Heavy system memory usage after reboot will nullify the benefits
291 // but the user will still pay the cost.
292 // - Overall the time saved will always be less than total time spent
293 // paging in chrome
294 // - We are not sure when the chrome 'warm up' will age out from the
295 // boot prefetch file.
297 // The idea here is to try this out on chrome frame dev channel
298 // and see if it produces a significant drift in startup numbers.
299 HRESULT SetupRunOnce() {
300 HRESULT result = E_FAIL;
302 string16 channel_name;
303 if (base::win::GetVersion() < base::win::VERSION_VISTA &&
304 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name)) {
305 std::transform(channel_name.begin(), channel_name.end(),
306 channel_name.begin(), tolower);
307 // Use this only for the dev channel.
308 if (channel_name.find(L"dev") != string16::npos) {
309 HKEY hive = HKEY_CURRENT_USER;
310 if (IsSystemProcess()) {
311 // For system installs, our updates will be running as SYSTEM which
312 // makes writing to a RunOnce key under HKCU not so terribly useful.
313 hive = HKEY_LOCAL_MACHINE;
316 RegKey run_once;
317 LONG ret = run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE);
318 if (ret == ERROR_SUCCESS) {
319 CommandLine run_once_cmd(chrome_launcher::GetChromeExecutablePath());
320 run_once_cmd.AppendSwitchASCII(switches::kAutomationClientChannelID,
321 "0");
322 run_once_cmd.AppendSwitch(switches::kChromeFrame);
323 ret = run_once.WriteValue(L"A",
324 run_once_cmd.GetCommandLineString().c_str());
326 result = HRESULT_FROM_WIN32(ret);
327 } else {
328 result = S_FALSE;
330 } else {
331 // We're on a non-XP version of Windows or on a stable channel. Nothing
332 // needs doing.
333 result = S_FALSE;
336 return result;
339 // Helper method called for user-level installs where we don't have admin
340 // permissions. Starts up the long running process and registers it to get it
341 // started at next boot.
342 HRESULT SetupUserLevelHelper() {
343 HRESULT hr = S_OK;
345 // Remove existing run-at-startup entry.
346 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
348 // Build the chrome_frame_helper command line.
349 base::FilePath module_path;
350 base::FilePath helper_path;
351 if (PathService::Get(base::FILE_MODULE, &module_path)) {
352 module_path = module_path.DirName();
353 helper_path = module_path.Append(kChromeFrameHelperExe);
354 if (!base::PathExists(helper_path)) {
355 // If we can't find the helper in the current directory, try looking
356 // one up (this is the layout in the build output folder).
357 module_path = module_path.DirName();
358 helper_path = module_path.Append(kChromeFrameHelperExe);
359 DCHECK(base::PathExists(helper_path)) <<
360 "Could not find chrome_frame_helper.exe.";
363 // Find window handle of existing instance.
364 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
365 kChromeFrameHelperWindowName);
367 if (base::PathExists(helper_path)) {
368 std::wstring helper_path_cmd(L"\"");
369 helper_path_cmd += helper_path.value();
370 helper_path_cmd += L"\" ";
371 helper_path_cmd += kChromeFrameHelperStartupArg;
373 // Add new run-at-startup entry.
374 if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
375 helper_path_cmd)) {
376 hr = E_FAIL;
377 LOG(ERROR) << "Could not add helper process to auto run key.";
380 // Start new instance.
381 base::LaunchOptions options;
382 options.start_hidden = true;
383 bool launched = base::LaunchProcess(helper_path.value(), options, NULL);
384 if (!launched) {
385 hr = E_FAIL;
386 PLOG(DFATAL) << "Could not launch helper process.";
389 // Kill old instance using window handle.
390 if (IsWindow(old_window)) {
391 BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
392 if (!result) {
393 PLOG(ERROR) << "Failed to post close message to old helper process: ";
396 } else {
397 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
399 } else {
400 hr = E_UNEXPECTED;
401 NOTREACHED();
404 return hr;
407 // To delete the user agent, set value to NULL.
408 // The is_system parameter indicates whether this is a per machine or a per
409 // user installation.
410 HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
411 HRESULT hr = E_FAIL;
412 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
414 RegKey ua_key;
415 LONG reg_result = ua_key.Create(parent_hive, kPostPlatformUAKey,
416 KEY_READ | KEY_WRITE);
417 if (reg_result == ERROR_SUCCESS) {
418 // Make sure that we unregister ChromeFrame UA strings registered previously
419 wchar_t value_name[MAX_PATH + 1] = {};
420 wchar_t value_data[MAX_PATH + 1] = {};
422 DWORD value_index = 0;
423 while (value_index < ua_key.GetValueCount()) {
424 DWORD name_size = arraysize(value_name);
425 DWORD value_size = arraysize(value_data);
426 DWORD type = 0;
427 LRESULT ret = ::RegEnumValue(ua_key.Handle(), value_index, value_name,
428 &name_size, NULL, &type,
429 reinterpret_cast<BYTE*>(value_data),
430 &value_size);
431 if (ret == ERROR_SUCCESS) {
432 if (StartsWith(value_name, kChromeFramePrefix, false)) {
433 ua_key.DeleteValue(value_name);
434 } else {
435 ++value_index;
437 } else {
438 break;
442 std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
443 chrome_frame_ua_value_name += GetCurrentModuleVersion();
444 if (value) {
445 ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value);
447 hr = S_OK;
448 } else {
449 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey
450 << ", error code = " << reg_result;
451 hr = HRESULT_FROM_WIN32(reg_result);
453 return hr;
456 class SecurityDescBackup {
457 public:
458 explicit SecurityDescBackup(const std::wstring& backup_key)
459 : backup_key_name_(backup_key) {}
460 ~SecurityDescBackup() {}
462 // Save given security descriptor to the backup key.
463 bool SaveSecurity(const CSecurityDesc& sd) {
464 CString str;
465 if (!sd.ToString(&str))
466 return false;
468 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
469 KEY_READ | KEY_WRITE);
470 if (backup_key.Valid()) {
471 return backup_key.WriteValue(NULL, str.GetString()) == ERROR_SUCCESS;
474 return false;
477 // Restore security descriptor from backup key to given key name.
478 bool RestoreSecurity(const wchar_t* key_name) {
479 std::wstring sddl;
480 if (!ReadBackupKey(&sddl))
481 return false;
483 // Create security descriptor from string.
484 CSecurityDesc sd;
485 if (!sd.FromString(sddl.c_str()))
486 return false;
488 bool result = true;
489 // Restore DACL and Owner of the key from saved security descriptor.
490 CDacl dacl;
491 CSid owner;
492 sd.GetDacl(&dacl);
493 sd.GetOwner(&owner);
495 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
496 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
497 const_cast<SID*>(owner.GetPSID()), NULL,
498 const_cast<ACL*>(dacl.GetPACL()), NULL);
500 DeleteBackupKey();
501 return (error == ERROR_SUCCESS);
504 private:
505 // Read SDDL string from backup key
506 bool ReadBackupKey(std::wstring* sddl) {
507 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
508 if (!backup_key.Valid())
509 return false;
511 DWORD len = 0;
512 DWORD reg_type = REG_NONE;
513 if (backup_key.ReadValue(NULL, NULL, &len, &reg_type) != ERROR_SUCCESS)
514 return false;
515 DCHECK_EQ(0u, len % sizeof(wchar_t));
517 if ((len == 0) || (reg_type != REG_SZ))
518 return false;
520 size_t wchar_count = 1 + len / sizeof(wchar_t);
521 if (backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
522 &reg_type) != ERROR_SUCCESS) {
523 return false;
526 return true;
529 void DeleteBackupKey() {
530 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
533 std::wstring backup_key_name_;
536 struct TokenWithPrivileges {
537 TokenWithPrivileges() {
538 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
539 token_.GetUser(&user_);
542 ~TokenWithPrivileges() {
543 token_.EnableDisablePrivileges(take_ownership_);
544 token_.EnableDisablePrivileges(restore_);
547 bool EnablePrivileges() {
548 if (take_ownership_.GetCount() == 0)
549 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
550 &take_ownership_))
551 return false;
553 if (restore_.GetCount() == 0)
554 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
555 return false;
557 return true;
560 const CSid& GetUser() const {
561 return user_;
564 private:
565 CAccessToken token_;
566 CTokenPrivileges take_ownership_;
567 CTokenPrivileges restore_;
568 CSid user_;
571 const wchar_t* const kMimeHandlerKeyValues[] = {
572 L"ChromeTab.ChromeActiveDocument",
573 L"ChromeTab.ChromeActiveDocument.1",
576 // Returns true if the values are present or absent in |root_key|'s Secure Mime
577 // Handlers key based on |for_installed|. Returns false if the values are not as
578 // expected or if an error occurred.
579 bool MimeHandlerKeyIsConfigured(bool for_install, HKEY root_key) {
580 string16 key_name(kInternetSettings);
581 key_name.append(L"\\Secure Mime Handlers");
582 RegKey key(root_key, key_name.c_str(), KEY_QUERY_VALUE);
583 if (!key.Valid())
584 return false;
586 for (size_t i = 0; i < arraysize(kMimeHandlerKeyValues); ++i) {
587 DWORD value = 0;
588 LONG result = key.ReadValueDW(kMimeHandlerKeyValues[i], &value);
589 if (for_install) {
590 if (result != ERROR_SUCCESS || value != 1)
591 return false;
592 } else {
593 if (result != ERROR_FILE_NOT_FOUND)
594 return false;
597 return true;
600 HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
601 string16 key_name(kInternetSettings);
602 key_name.append(L"\\Secure Mime Handlers");
603 RegKey key(root_key, key_name.c_str(), KEY_SET_VALUE);
604 if (!key.Valid())
605 return false;
607 HRESULT result = S_OK;
608 for (size_t i = 0; i < arraysize(kMimeHandlerKeyValues); ++i) {
609 LONG intermediate = set ?
610 key.WriteValue(kMimeHandlerKeyValues[i], 1) :
611 key.DeleteValue(kMimeHandlerKeyValues[i]);
612 if (intermediate != ERROR_SUCCESS && result == S_OK)
613 result = HRESULT_FROM_WIN32(intermediate);
615 return result;
618 void OnPinModule() {
619 // Pin crash reporting by leaking a reference.
620 ignore_result(new chrome_frame::ScopedCrashReporting());
623 // Chrome Frame registration functions.
624 //-----------------------------------------------------------------------------
625 HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
626 if (MimeHandlerKeyIsConfigured(enable, HKEY_LOCAL_MACHINE))
627 return S_OK;
628 if (!is_system)
629 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
630 if (base::win::GetVersion() < base::win::VERSION_VISTA)
631 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
633 std::wstring mime_key = kInternetSettings;
634 mime_key.append(L"\\Secure Mime Handlers");
635 std::wstring backup_key = kInternetSettings;
636 backup_key.append(L"\\__backup_SMH__");
637 std::wstring object_name = L"MACHINE\\";
638 object_name.append(mime_key);
640 TokenWithPrivileges token_;
641 if (!token_.EnablePrivileges())
642 return E_ACCESSDENIED;
644 // If there is a backup key - something bad happened; try to restore
645 // security on "Secure Mime Handlers" from the backup.
646 SecurityDescBackup backup(backup_key);
647 backup.RestoreSecurity(object_name.c_str());
649 // Read old security descriptor of the Mime key first.
650 CSecurityDesc sd;
651 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
652 return E_FAIL;
655 backup.SaveSecurity(sd);
656 HRESULT hr = E_FAIL;
657 // set new owner
658 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
659 // set new dacl
660 CDacl new_dacl;
661 sd.GetDacl(&new_dacl);
662 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
663 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
664 hr = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
668 backup.RestoreSecurity(object_name.c_str());
669 return hr;
672 HRESULT RegisterActiveDoc(bool reg, bool is_system) {
673 // We have to call the static T::UpdateRegistry function instead of
674 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg)
675 // because there is specific OLEMISC replacement.
676 return ChromeActiveDocument::UpdateRegistry(reg);
679 HRESULT RegisterActiveX(bool reg, bool is_system) {
680 // We have to call the static T::UpdateRegistry function instead of
681 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
682 // because there is specific OLEMISC replacement.
683 return ChromeFrameActivex::UpdateRegistry(reg);
686 HRESULT RegisterElevationPolicy(bool reg, bool is_system) {
687 HRESULT hr = S_OK;
688 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
689 // Register the elevation policy. This must succeed for Chrome Frame to
690 // be able launch Chrome when running in low-integrity IE.
691 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION, reg);
692 if (SUCCEEDED(hr)) {
693 // Ignore failures since old versions of IE 7 (e.g., 7.0.6000.16386, which
694 // shipped with Vista RTM) do not export IERefreshElevationPolicy.
695 RefreshElevationPolicy();
698 return hr;
701 HRESULT RegisterProtocol(bool reg, bool is_system) {
702 return _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
705 HRESULT RegisterBhoClsid(bool reg, bool is_system) {
706 return Bho::UpdateRegistry(reg);
709 HRESULT RegisterBhoIE(bool reg, bool is_system) {
710 if (is_system) {
711 return _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
712 } else {
713 if (reg) {
714 // Setup the long running process:
715 return SetupUserLevelHelper();
716 } else {
717 // Unschedule the user-level helper. Note that we don't kill it here
718 // so that during updates we don't have a time window with no running
719 // helper. Uninstalls and updates will explicitly kill the helper from
720 // within the installer. Unregister existing run-at-startup entry.
721 return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER,
722 kRunKeyName) ? S_OK : E_FAIL;
727 HRESULT RegisterTypeLib(bool reg, bool is_system) {
728 if (reg && !is_system) {
729 // Enables the RegisterTypeLib Function function to override default
730 // registry mappings under Windows Vista Service Pack 1 (SP1),
731 // Windows Server 2008, and later operating system versions
732 typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
733 OaEnablePerUserTypeLibReg per_user_typelib_func =
734 reinterpret_cast<OaEnablePerUserTypeLibReg>(
735 GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
736 "OaEnablePerUserTLibRegistration"));
737 if (per_user_typelib_func) {
738 (*per_user_typelib_func)();
741 return reg ?
742 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
743 NULL, !is_system) :
744 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib,
745 NULL, !is_system);
748 HRESULT RegisterLegacyNPAPICleanup(bool reg, bool is_system) {
749 if (!reg) {
750 _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
751 UtilRemovePersistentNPAPIMarker();
753 // Ignore failures.
754 return S_OK;
757 HRESULT RegisterAppId(bool reg, bool is_system) {
758 return _AtlModule.UpdateRegistryAppId(reg);
761 HRESULT RegisterUserAgent(bool reg, bool is_system) {
762 if (reg) {
763 return SetChromeFrameUA(is_system, L"1");
764 } else {
765 return SetChromeFrameUA(is_system, NULL);
769 enum RegistrationStepId {
770 kStepSecuredMimeHandler = 0,
771 kStepActiveDoc = 1,
772 kStepActiveX = 2,
773 kStepElevationPolicy = 3,
774 kStepProtocol = 4,
775 kStepBhoClsid = 5,
776 kStepBhoRegistration = 6,
777 kStepRegisterTypeLib = 7,
778 kStepNpapiCleanup = 8,
779 kStepAppId = 9,
780 kStepUserAgent = 10,
781 kStepEnd = 11
784 enum RegistrationFlags {
785 ACTIVEX = 0x0001,
786 ACTIVEDOC = 0x0002,
787 GCF_PROTOCOL = 0x0004,
788 BHO_CLSID = 0x0008,
789 BHO_REGISTRATION = 0x0010,
790 TYPELIB = 0x0020,
792 ALL = 0xFFFF
795 // Mux the failure step into the hresult. We take only the first four bits
796 // and stick those into the top four bits of the facility code. We also set the
797 // Customer bit to be polite. Graphically, we write our error code to the
798 // bits marked with ^:
799 // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
800 // 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
801 // +---+-+-+-----------------------+-------------------------------+
802 // |Sev|C|R| Facility | Code |
803 // +---+-+-+-----------------------+-------------------------------+
804 // ^ ^ ^ ^ ^
805 // See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for
806 // more details on HRESULTS.
808 // The resulting error can be extracted by:
809 // error_code = (fiddled_hr & 0x07800000) >> 23
810 HRESULT MuxErrorIntoHRESULT(HRESULT hr, int error_code) {
811 DCHECK_GE(error_code, 0);
812 DCHECK_LT(error_code, kStepEnd);
813 COMPILE_ASSERT(kStepEnd <= 0xF, update_error_muxing_too_many_steps);
815 // Check that our four desired bits are clear.
816 // 0xF87FFFFF == 11111000011111111111111111111111
817 DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr);
819 HRESULT fiddled_hr = ((error_code & 0xF) << 23) | hr;
820 fiddled_hr |= 1 << 29; // Set the customer bit.
822 return fiddled_hr;
825 HRESULT CustomRegistration(uint16 reg_flags, bool reg, bool is_system) {
826 if (reg && (reg_flags & (ACTIVEDOC | ACTIVEX)))
827 reg_flags |= (TYPELIB | GCF_PROTOCOL);
829 // Set the flag that gets checked in AddCommonRGSReplacements before doing
830 // registration work.
831 _AtlModule.do_system_registration_ = is_system;
833 typedef HRESULT (*RegistrationFn)(bool reg, bool is_system);
834 struct RegistrationStep {
835 RegistrationStepId id;
836 uint16 condition;
837 RegistrationFn func;
839 static const RegistrationStep registration_steps[] = {
840 { kStepSecuredMimeHandler, ACTIVEDOC, &RegisterSecuredMimeHandler },
841 { kStepActiveDoc, ACTIVEDOC, &RegisterActiveDoc },
842 { kStepActiveX, ACTIVEX, &RegisterActiveX },
843 { kStepElevationPolicy, (ACTIVEDOC | ACTIVEX), &RegisterElevationPolicy },
844 { kStepProtocol, GCF_PROTOCOL, &RegisterProtocol },
845 { kStepBhoClsid, BHO_CLSID, &RegisterBhoClsid },
846 { kStepBhoRegistration, BHO_REGISTRATION, &RegisterBhoIE },
847 { kStepRegisterTypeLib, TYPELIB, &RegisterTypeLib },
848 { kStepNpapiCleanup, ALL, &RegisterLegacyNPAPICleanup },
849 { kStepAppId, ALL, &RegisterAppId },
850 { kStepUserAgent, ALL, &RegisterUserAgent }
853 HRESULT hr = S_OK;
855 bool rollback = false;
856 int failure_step = 0;
857 HRESULT step_hr = S_OK;
858 for (int step = 0; step < arraysize(registration_steps); ++step) {
859 if ((reg_flags & registration_steps[step].condition) != 0) {
860 step_hr = registration_steps[step].func(reg, is_system);
861 if (FAILED(step_hr)) {
862 // Store only the first failing HRESULT with the step value muxed in.
863 if (hr == S_OK) {
864 hr = MuxErrorIntoHRESULT(step_hr, step);
867 // On registration if a step fails, we abort and rollback.
868 if (reg) {
869 rollback = true;
870 failure_step = step;
871 break;
877 if (rollback) {
878 DCHECK(reg);
879 // Rollback the failing action and all preceding ones.
880 for (int step = failure_step; step >= 0; --step) {
881 registration_steps[step].func(!reg, is_system);
885 return hr;
888 } // namespace
890 // DLL Entry Point
891 extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
892 DWORD reason,
893 LPVOID reserved) {
894 UNREFERENCED_PARAMETER(instance);
895 if (reason == DLL_PROCESS_ATTACH) {
896 #if _ATL_VER < 0x0C00 && !defined(NDEBUG)
897 // Silence traces from the ATL registrar to reduce the log noise.
898 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
899 ATLTRACESTATUS_DISABLED);
900 #endif
901 InitGoogleUrl();
903 g_exit_manager = new base::AtExitManager();
904 CommandLine::Init(0, NULL);
905 logging::LoggingSettings settings;
906 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
907 logging::InitLogging(settings);
909 // Log the same items as Chrome.
910 logging::SetLogItems(true, // enable_process_id
911 true, // enable_thread_id
912 false, // enable_timestamp
913 true); // enable_tickcount
915 DllRedirector* dll_redirector = DllRedirector::GetInstance();
916 DCHECK(dll_redirector);
918 if (!dll_redirector->RegisterAsFirstCFModule()) {
919 // Someone else was here first, try and get a pointer to their
920 // DllGetClassObject export:
921 g_dll_get_class_object_redir_ptr =
922 dll_redirector->GetDllGetClassObjectPtr();
923 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
924 << "Found CF module with no DllGetClassObject export.";
927 // Enable trace control and transport through event tracing for Windows.
928 logging::LogEventProvider::Initialize(kChromeFrameProvider);
930 // Set a callback so that crash reporting can be pinned when the module is
931 // pinned.
932 chrome_frame::SetPinModuleCallback(&OnPinModule);
933 } else if (reason == DLL_PROCESS_DETACH) {
934 DllRedirector* dll_redirector = DllRedirector::GetInstance();
935 DCHECK(dll_redirector);
936 dll_redirector->UnregisterAsFirstCFModule();
938 g_patch_helper.UnpatchIfNeeded();
940 delete g_exit_manager;
941 g_exit_manager = NULL;
943 return _AtlModule.DllMain(reason, reserved);
946 // Used to determine whether the DLL can be unloaded by OLE
947 STDAPI DllCanUnloadNow() {
948 return _AtlModule.DllCanUnloadNow();
951 // Returns a class factory to create an object of the requested type
952 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
953 chrome_frame::ScopedCrashReporting crash_reporting;
955 // IE 11+ are unsupported.
956 if (GetIEVersion() > IE_10) {
957 return CLASS_E_CLASSNOTAVAILABLE;
960 // If we found another module present when we were loaded, then delegate to
961 // that:
962 if (g_dll_get_class_object_redir_ptr) {
963 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
966 // Enable sniffing and switching only if asked for BHO
967 // (we use BHO to get loaded in IE).
968 if (rclsid == CLSID_ChromeFrameBHO) {
969 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
972 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
975 // DllRegisterServer - Adds entries to the system registry
976 STDAPI DllRegisterServer() {
977 chrome_frame::ScopedCrashReporting crash_reporting;
978 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
979 BHO_CLSID | BHO_REGISTRATION;
981 HRESULT hr = CustomRegistration(flags, true, true);
982 if (SUCCEEDED(hr)) {
983 SetupRunOnce();
986 return hr;
989 // DllUnregisterServer - Removes entries from the system registry
990 STDAPI DllUnregisterServer() {
991 chrome_frame::ScopedCrashReporting crash_reporting;
992 HRESULT hr = CustomRegistration(ALL, false, true);
993 return hr;
996 // DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
997 STDAPI DllRegisterUserServer() {
998 chrome_frame::ScopedCrashReporting crash_reporting;
999 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
1000 BHO_CLSID | BHO_REGISTRATION;
1002 HRESULT hr = CustomRegistration(flags, TRUE, false);
1003 if (SUCCEEDED(hr)) {
1004 SetupRunOnce();
1007 return hr;
1010 // DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
1011 STDAPI DllUnregisterUserServer() {
1012 chrome_frame::ScopedCrashReporting crash_reporting;
1013 HRESULT hr = CustomRegistration(ALL, FALSE, false);
1014 return hr;
1017 // Object entries go here instead of with each object, so that we can move
1018 // the objects to a lib. Also reduces magic.
1019 OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
1020 OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
1021 OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
1022 OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)