blob: b7d289844b934c120e1bb97c9fa4e6a53db52300 [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"
[email protected]f7817822009-09-24 05:11:5816#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]cebd4132010-03-25 15:34:2255}
[email protected]f7817822009-09-24 05:11:5856
[email protected]f7817822009-09-24 05:11:5857static const wchar_t kBhoRegistryPath[] =
58 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
59 L"\\Browser Helper Objects";
60
[email protected]357219de2009-10-06 23:40:2261const wchar_t kInternetSettings[] =
62 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
63
[email protected]552fb6012010-02-03 17:24:2964const wchar_t kProtocolHandlers[] =
65 L"Software\\Classes\\Protocols\\Handler";
66
[email protected]02ea78a2010-07-15 16:52:2867const wchar_t kRunOnce[] =
68 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
69
[email protected]c5c6c8c2010-09-07 13:57:2170const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
71
72const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
73
74// Window class and window names.
75// TODO(robertshield): These and other constants need to be refactored into
76// a common chrome_frame_constants.h|cc and built into a separate lib
77// (either chrome_frame_utils or make another one).
78const wchar_t kChromeFrameHelperWindowClassName[] =
79 L"ChromeFrameHelperWindowClass";
80const wchar_t kChromeFrameHelperWindowName[] =
81 L"ChromeFrameHelperWindowName";
[email protected]f7817822009-09-24 05:11:5882
[email protected]5ee34132009-11-25 21:32:2683// {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
84static const GUID kChromeFrameProvider =
85 { 0x562bfc3, 0x2550, 0x45b4,
86 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
87
[email protected]ea9ed97d2010-01-05 19:16:2388// Object entries go here instead of with each object, so that we can move
89// the objects to a lib. Also reduces magic.
90OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
91OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
92OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
93OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)
[email protected]5ee34132009-11-25 21:32:2694
[email protected]8adbf7e52010-04-14 20:03:2395
96// See comments in DllGetClassObject.
[email protected]52749842010-05-07 21:34:4197LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
[email protected]8adbf7e52010-04-14 20:03:2398
[email protected]6bdc0c02010-07-20 14:52:1399class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
[email protected]f7817822009-09-24 05:11:58100 public:
[email protected]6bdc0c02010-07-20 14:52:13101 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
[email protected]f7817822009-09-24 05:11:58102
[email protected]59b34a72010-09-01 17:30:35103 ChromeTabModule() : do_system_registration_(true) {}
104
[email protected]f7817822009-09-24 05:11:58105 DECLARE_LIBID(LIBID_ChromeTabLib)
106 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
107 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
108
109 // Override to add our SYSTIME binary value to registry scripts.
110 // See chrome_frame_activex.rgs for usage.
111 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
112 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
113
114 if (SUCCEEDED(hr)) {
115 SYSTEMTIME local_time;
116 ::GetSystemTime(&local_time);
[email protected]c9c077792010-08-03 14:39:42117 std::string hex(base::HexEncode(&local_time, sizeof(local_time)));
[email protected]f7817822009-09-24 05:11:58118 base::StringPiece sp_hex(hex);
119 hr = registrar->AddReplacement(L"SYSTIME",
120 base::SysNativeMBToWide(sp_hex).c_str());
121 DCHECK(SUCCEEDED(hr));
122 }
123
124 if (SUCCEEDED(hr)) {
[email protected]66ff7352009-10-15 05:09:50125 FilePath app_path =
126 chrome_launcher::GetChromeExecutablePath().DirName();
127 hr = registrar->AddReplacement(L"CHROME_APPPATH",
128 app_path.value().c_str());
[email protected]f7817822009-09-24 05:11:58129 DCHECK(SUCCEEDED(hr));
130 }
131
132 if (SUCCEEDED(hr)) {
133 hr = registrar->AddReplacement(L"CHROME_APPNAME",
134 chrome::kBrowserProcessExecutableName);
135 DCHECK(SUCCEEDED(hr));
136
137 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
138 scoped_ptr<FileVersionInfo> module_version_info(
139 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
140 DCHECK(module_version_info != NULL);
141 std::wstring file_version(module_version_info->file_version());
142 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
143 DCHECK(SUCCEEDED(hr));
144 }
145
146 if (SUCCEEDED(hr)) {
147 // Add the directory of chrome_launcher.exe. This will be the same
148 // as the directory for the current DLL.
149 std::wstring module_dir;
150 FilePath module_path;
151 if (PathService::Get(base::FILE_MODULE, &module_path)) {
[email protected]466a9222010-06-08 01:03:16152 module_dir = module_path.DirName().value();
[email protected]f7817822009-09-24 05:11:58153 } else {
154 NOTREACHED();
155 }
156 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
157 module_dir.c_str());
158 DCHECK(SUCCEEDED(hr));
159 }
160
161 if (SUCCEEDED(hr)) {
162 // Add the filename of chrome_launcher.exe
163 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
164 chrome_launcher::kLauncherExeBaseName);
165 DCHECK(SUCCEEDED(hr));
166 }
167
[email protected]59b34a72010-09-01 17:30:35168 if (SUCCEEDED(hr)) {
169 // Add the registry hive to use.
170 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
171 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
172 // few components that are registered by calling their
173 // static T::UpdateRegistry() methods directly, which doesn't allow
174 // pMapEntries to be passed through :-(
175 if (do_system_registration_) {
176 hr = registrar->AddReplacement(L"HIVE", L"HKLM");
177 } else {
178 hr = registrar->AddReplacement(L"HIVE", L"HKCU");
179 }
180 DCHECK(SUCCEEDED(hr));
181 }
182
[email protected]f7817822009-09-24 05:11:58183 return hr;
184 }
[email protected]59b34a72010-09-01 17:30:35185
186 // See comments in AddCommonRGSReplacements
187 bool do_system_registration_;
[email protected]f7817822009-09-24 05:11:58188};
189
190ChromeTabModule _AtlModule;
191
192base::AtExitManager* g_exit_manager = NULL;
[email protected]59b34a72010-09-01 17:30:35193bool RegisterSecuredMimeHandler(bool enable, bool is_system); // forward
[email protected]f7817822009-09-24 05:11:58194
195// DLL Entry Point
196extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
197 DWORD reason,
198 LPVOID reserved) {
199 UNREFERENCED_PARAMETER(instance);
200 if (reason == DLL_PROCESS_ATTACH) {
201#ifndef NDEBUG
202 // Silence traces from the ATL registrar to reduce the log noise.
203 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
204 ATLTRACESTATUS_DISABLED);
205#endif
[email protected]cebd4132010-03-25 15:34:22206 InitGoogleUrl();
207
[email protected]c41468f2009-11-11 20:39:18208 g_exit_manager = new base::AtExitManager();
[email protected]74d1eec2009-11-04 22:18:57209 CommandLine::Init(0, NULL);
[email protected]53556e12009-10-15 21:49:22210 InitializeCrashReporting();
[email protected]7c10f7552011-01-11 01:03:36211 logging::InitLogging(
212 NULL,
213 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
214 logging::LOCK_LOG_FILE,
215 logging::DELETE_OLD_LOG_FILE,
216 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
[email protected]52749842010-05-07 21:34:41217
[email protected]687b9602010-12-08 10:43:08218 DllRedirector* dll_redirector = DllRedirector::GetInstance();
[email protected]8cc41942010-11-05 19:16:07219 DCHECK(dll_redirector);
220
221 if (!dll_redirector->RegisterAsFirstCFModule()) {
222 // Someone else was here first, try and get a pointer to their
223 // DllGetClassObject export:
224 g_dll_get_class_object_redir_ptr =
225 dll_redirector->GetDllGetClassObjectPtr();
226 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
227 << "Found CF module with no DllGetClassObject export.";
[email protected]52749842010-05-07 21:34:41228 }
229
[email protected]5ee34132009-11-25 21:32:26230 // Enable ETW logging.
231 logging::LogEventProvider::Initialize(kChromeFrameProvider);
[email protected]f7817822009-09-24 05:11:58232 } else if (reason == DLL_PROCESS_DETACH) {
[email protected]687b9602010-12-08 10:43:08233 DllRedirector* dll_redirector = DllRedirector::GetInstance();
[email protected]8cc41942010-11-05 19:16:07234 DCHECK(dll_redirector);
235
236 dll_redirector->UnregisterAsFirstCFModule();
[email protected]f7817822009-09-24 05:11:58237 g_patch_helper.UnpatchIfNeeded();
238 delete g_exit_manager;
239 g_exit_manager = NULL;
240 ShutdownCrashReporting();
241 }
242 return _AtlModule.DllMain(reason, reserved);
243}
244
245#ifdef _MANAGED
246#pragma managed(pop)
247#endif
248
[email protected]f7817822009-09-24 05:11:58249HRESULT RefreshElevationPolicy() {
250 const wchar_t kIEFrameDll[] = L"ieframe.dll";
251 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
252 HRESULT hr = E_NOTIMPL;
[email protected]1f08d682010-05-19 18:48:31253
254 // Stick an SEH in the chain to prevent the VEH from picking up on first
255 // chance exceptions caused by loading ieframe.dll. Use the vanilla
256 // ExceptionBarrier to report any exceptions that do make their way to us
257 // though.
258 ExceptionBarrier barrier;
259
[email protected]f7817822009-09-24 05:11:58260 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
261 if (ieframe_module) {
262 typedef HRESULT (__stdcall *IERefreshPolicy)();
263 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
264 GetProcAddress(ieframe_module, kIERefreshPolicy));
265
266 if (ie_refresh_policy) {
267 hr = ie_refresh_policy();
268 } else {
269 hr = HRESULT_FROM_WIN32(GetLastError());
270 }
[email protected]357219de2009-10-06 23:40:22271
[email protected]f7817822009-09-24 05:11:58272 FreeLibrary(ieframe_module);
273 } else {
274 hr = HRESULT_FROM_WIN32(GetLastError());
275 }
276
277 return hr;
278}
279
[email protected]02ea78a2010-07-15 16:52:28280// Experimental boot prefetch optimization for Chrome Frame
281//
282// If chrome is warmed up during a single reboot, it gets paged
283// in for subsequent reboots and the cold startup times essentially
284// look like warm times thereafter! The 'warm up' is done by
285// setting up a 'RunOnce' key during DLLRegisterServer of
286// npchrome_frame.dll.
287//
288// This works because chrome prefetch becomes part of boot
289// prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
290// reboots. As long as the sytem does not undergo significant
291// memory pressure those pages remain in memory and we get pretty
292// amazing startup times, down to about 300 ms from 1200 ms
293//
294// The downside is:
295// - Whether chrome frame is used or not, there's a read penalty
296// (1200-300 =) 900 ms for every boot.
297// - Heavy system memory usage after reboot will nullify the benefits
298// but the user will still pay the cost.
299// - Overall the time saved will always be less than total time spent
300// paging in chrome
301// - We are not sure when the chrome 'warm up' will age out from the
302// boot prefetch file.
303//
304// The idea here is to try this out on chrome frame dev channel
305// and see if it produces a significant drift in startup numbers.
306HRESULT SetupRunOnce() {
[email protected]7fc3e6922010-11-18 17:56:54307 HRESULT result = E_FAIL;
[email protected]02ea78a2010-07-15 16:52:28308
309 std::wstring channel_name;
[email protected]7fc3e6922010-11-18 17:56:54310 if (base::win::GetVersion() < base::win::VERSION_VISTA &&
[email protected]3e76e27b2011-05-02 21:19:01311 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name)) {
[email protected]7fc3e6922010-11-18 17:56:54312 std::transform(channel_name.begin(), channel_name.end(),
313 channel_name.begin(), tolower);
314 // Use this only for the dev channel and CEEE channels.
315 if (channel_name.find(L"dev") != std::wstring::npos ||
316 channel_name.find(L"ceee") != std::wstring::npos) {
[email protected]542bdfe2010-11-30 03:55:47317
[email protected]7fc3e6922010-11-18 17:56:54318 HKEY hive = HKEY_CURRENT_USER;
319 if (IsSystemProcess()) {
320 // For system installs, our updates will be running as SYSTEM which
321 // makes writing to a RunOnce key under HKCU not so terribly useful.
322 hive = HKEY_LOCAL_MACHINE;
323 }
[email protected]74ecb5a42010-09-03 00:44:35324
[email protected]7fc3e6922010-11-18 17:56:54325 RegKey run_once;
[email protected]e06f4d52011-01-19 07:28:46326 LONG ret = run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE);
327 if (ret == ERROR_SUCCESS) {
[email protected]7fc3e6922010-11-18 17:56:54328 CommandLine run_once_cmd(chrome_launcher::GetChromeExecutablePath());
329 run_once_cmd.AppendSwitchASCII(switches::kAutomationClientChannelID,
[email protected]05076ba22010-07-30 05:59:57330 "0");
[email protected]7fc3e6922010-11-18 17:56:54331 run_once_cmd.AppendSwitch(switches::kChromeFrame);
[email protected]e06f4d52011-01-19 07:28:46332 ret = run_once.WriteValue(L"A",
333 run_once_cmd.command_line_string().c_str());
[email protected]7fc3e6922010-11-18 17:56:54334 }
[email protected]e06f4d52011-01-19 07:28:46335 result = HRESULT_FROM_WIN32(ret);
[email protected]7fc3e6922010-11-18 17:56:54336 } else {
337 result = S_FALSE;
338 }
339 } else {
340 // We're on a non-XP version of Windows or on a stable channel. Nothing
341 // needs doing.
342 result = S_FALSE;
[email protected]552fb6012010-02-03 17:24:29343 }
344
[email protected]7fc3e6922010-11-18 17:56:54345 return result;
[email protected]552fb6012010-02-03 17:24:29346}
347
[email protected]c5c6c8c2010-09-07 13:57:21348// Helper method called for user-level installs where we don't have admin
349// permissions. Starts up the long running process and registers it to get it
350// started at next boot.
351void SetupUserLevelHelper() {
352 // Remove existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50353 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21354
355 // Build the chrome_frame_helper command line.
356 FilePath module_path;
357 FilePath helper_path;
358 if (PathService::Get(base::FILE_MODULE, &module_path)) {
359 module_path = module_path.DirName();
360 helper_path = module_path.Append(kChromeFrameHelperExe);
361 if (!file_util::PathExists(helper_path)) {
362 // If we can't find the helper in the current directory, try looking
363 // one up (this is the layout in the build output folder).
364 module_path = module_path.DirName();
365 helper_path = module_path.Append(kChromeFrameHelperExe);
366 DCHECK(file_util::PathExists(helper_path)) <<
367 "Could not find chrome_frame_helper.exe.";
368 }
369 } else {
370 NOTREACHED();
371 }
372
373 // Find window handle of existing instance.
374 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
375 kChromeFrameHelperWindowName);
376
377 if (file_util::PathExists(helper_path)) {
378 // Add new run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50379 base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
[email protected]c5c6c8c2010-09-07 13:57:21380 helper_path.value());
381
382 // Start new instance.
383 bool launched = base::LaunchApp(helper_path.value(), false, true, NULL);
384 if (!launched) {
385 NOTREACHED();
386 LOG(ERROR) << "Could not launch helper process.";
387 }
388
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 LOG(ERROR) << "Failed to post close message to old helper process: "
394 << GetLastError();
395 }
396 }
397 }
398}
399
400
[email protected]f7817822009-09-24 05:11:58401// Used to determine whether the DLL can be unloaded by OLE
402STDAPI DllCanUnloadNow() {
403 return _AtlModule.DllCanUnloadNow();
404}
405
406// Returns a class factory to create an object of the requested type
407STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
[email protected]52749842010-05-07 21:34:41408 // If we found another module present when we were loaded, then delegate to
409 // that:
410 if (g_dll_get_class_object_redir_ptr) {
411 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
[email protected]8adbf7e52010-04-14 20:03:23412 }
[email protected]ee54aec92010-07-21 15:52:24413
414 // Enable sniffing and switching only if asked for BHO
415 // (we use BHO to get loaded in IE).
416 if (rclsid == CLSID_ChromeFrameBHO) {
417 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
418 }
419
420 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
[email protected]f7817822009-09-24 05:11:58421}
422
[email protected]6a8515e42010-12-16 19:38:52423const wchar_t kPostPlatformUAKey[] =
424 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
425 L"User Agent\\Post Platform";
426const wchar_t kChromeFramePrefix[] = L"chromeframe/";
427
428// To delete the user agent, set value to NULL.
429// The is_system parameter indicates whether this is a per machine or a per
430// user installation.
431HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
432 HRESULT hr = E_FAIL;
433 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
434
435 RegKey ua_key;
[email protected]e06f4d52011-01-19 07:28:46436 if (ua_key.Create(parent_hive, kPostPlatformUAKey,
437 KEY_READ | KEY_WRITE) == ERROR_SUCCESS) {
[email protected]45b716b2011-01-14 18:43:53438 // Make sure that we unregister ChromeFrame UA strings registered previously
[email protected]9b7baa962011-01-14 20:07:07439 wchar_t value_name[MAX_PATH + 1] = {};
440 wchar_t value_data[MAX_PATH + 1] = {};
[email protected]45b716b2011-01-14 18:43:53441
442 DWORD value_index = 0;
443 while (value_index < ua_key.ValueCount()) {
[email protected]9b7baa962011-01-14 20:07:07444 DWORD name_size = arraysize(value_name);
445 DWORD value_size = arraysize(value_data);
[email protected]45b716b2011-01-14 18:43:53446 DWORD type = 0;
[email protected]9b7baa962011-01-14 20:07:07447 LRESULT ret = ::RegEnumValue(ua_key.Handle(), value_index, value_name,
[email protected]45b716b2011-01-14 18:43:53448 &name_size, NULL, &type,
[email protected]9b7baa962011-01-14 20:07:07449 reinterpret_cast<BYTE*>(value_data),
[email protected]45b716b2011-01-14 18:43:53450 &value_size);
451 if (ret == ERROR_SUCCESS) {
[email protected]9b7baa962011-01-14 20:07:07452 if (StartsWith(value_name, kChromeFramePrefix, false)) {
453 ua_key.DeleteValue(value_name);
[email protected]45b716b2011-01-14 18:43:53454 } else {
455 ++value_index;
456 }
457 } else {
458 break;
459 }
460 }
461
[email protected]6a8515e42010-12-16 19:38:52462 std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
463 chrome_frame_ua_value_name += GetCurrentModuleVersion();
464 if (value) {
465 ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value);
[email protected]6a8515e42010-12-16 19:38:52466 }
467 hr = S_OK;
468 } else {
469 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey;
470 hr = E_UNEXPECTED;
471 }
472 return hr;
473}
474
[email protected]ee54aec92010-07-21 15:52:24475enum RegistrationFlags {
476 ACTIVEX = 0x0001,
477 ACTIVEDOC = 0x0002,
478 GCF_PROTOCOL = 0x0004,
479 BHO_CLSID = 0x0008,
480 BHO_REGISTRATION = 0x0010,
481 TYPELIB = 0x0020,
482
483 NPAPI_PLUGIN = 0x1000,
484
485 ALL = 0xFFFF
486};
487
[email protected]59b34a72010-09-01 17:30:35488STDAPI CustomRegistration(UINT reg_flags, BOOL reg, bool is_system) {
[email protected]ee54aec92010-07-21 15:52:24489 UINT flags = reg_flags;
490
491 if (reg && (flags & (ACTIVEDOC | ACTIVEX)))
[email protected]0fcfffb2011-02-03 19:35:22492 flags |= (TYPELIB | GCF_PROTOCOL);
[email protected]ee54aec92010-07-21 15:52:24493
494 HRESULT hr = S_OK;
495
[email protected]59b34a72010-09-01 17:30:35496 // Set the flag that gets checked in AddCommonRGSReplacements before doing
497 // registration work.
498 _AtlModule.do_system_registration_ = is_system;
499
[email protected]ee54aec92010-07-21 15:52:24500 if ((hr == S_OK) && (flags & ACTIVEDOC)) {
[email protected]59b34a72010-09-01 17:30:35501 // Don't fail to unregister if we can't undo the secure mime
502 // handler registration. This was observed getting hit during
503 // uninstallation.
504 if (!RegisterSecuredMimeHandler(reg ? true : false, is_system) && reg)
[email protected]ee54aec92010-07-21 15:52:24505 return E_FAIL;
506 hr = ChromeActiveDocument::UpdateRegistry(reg);
507 }
508
509 if ((hr == S_OK) && (flags & ACTIVEX)) {
510 // We have to call the static T::UpdateRegistry function instead of
511 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg)
512 // because there is specific OLEMISC replacement.
513 hr = ChromeFrameActivex::UpdateRegistry(reg);
[email protected]0fcfffb2011-02-03 19:35:22514 }
515
516 // Register the elevation policy. We do this only for developer convenience
517 // as the installer is really responsible for doing this.
518 // Because of that, we do not unregister this policy and just leave that up
519 // to the installer.
520 if (hr == S_OK && (flags & (ACTIVEDOC | ACTIVEX)) && reg) {
521 _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION, reg);
[email protected]0f5945b12010-08-11 21:03:30522 RefreshElevationPolicy();
[email protected]ee54aec92010-07-21 15:52:24523 }
524
525 if ((hr == S_OK) && (flags & GCF_PROTOCOL)) {
526 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
527 }
528
529 if ((hr == S_OK) && (flags & BHO_CLSID)) {
530 hr = Bho::UpdateRegistry(reg);
531 }
532
[email protected]c5c6c8c2010-09-07 13:57:21533 if ((hr == S_OK) && (flags & BHO_REGISTRATION)) {
534 if (is_system) {
535 _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
536 } else {
537 if (reg) {
538 // Setup the long running process:
539 SetupUserLevelHelper();
540 } else {
541 // Unschedule the user-level helper. Note that we don't kill it here so
542 // that during updates we don't have a time window with no running
543 // helper. Uninstalls and updates will explicitly kill the helper from
544 // within the installer. Unregister existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50545 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21546 }
547 }
[email protected]ee54aec92010-07-21 15:52:24548 }
549
550 if ((hr == S_OK) && (flags & TYPELIB)) {
[email protected]e6190aa2011-02-04 19:36:14551 if (reg && !is_system) {
552 // Enables the RegisterTypeLib Function function to override default
553 // registry mappings under Windows Vista Service Pack 1 (SP1),
554 // Windows Server 2008, and later operating system versions
555 typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void);
556 OaEnablePerUserTypeLibReg per_user_typelib_func =
557 reinterpret_cast<OaEnablePerUserTypeLibReg>(
558 GetProcAddress(GetModuleHandle(L"oleaut32.dll"),
559 "OaEnablePerUserTLibRegistration"));
560 if (per_user_typelib_func) {
561 (*per_user_typelib_func)();
562 }
563 }
[email protected]59b34a72010-09-01 17:30:35564 hr = (reg)?
565 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system) :
566 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system);
[email protected]ee54aec92010-07-21 15:52:24567 }
568
569 if ((hr == S_OK) && (flags & NPAPI_PLUGIN)) {
570 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
571 }
572
573 if (hr == S_OK) {
574 hr = _AtlModule.UpdateRegistryAppId(reg);
575 }
576
[email protected]6a8515e42010-12-16 19:38:52577 if (hr == S_OK) {
578 if (reg) {
579 hr = SetChromeFrameUA(is_system, L"1");
580 } else {
581 hr = SetChromeFrameUA(is_system, NULL);
582 }
583 }
[email protected]ee54aec92010-07-21 15:52:24584 return hr;
585}
586
587
588
[email protected]f7817822009-09-24 05:11:58589// DllRegisterServer - Adds entries to the system registry
590STDAPI DllRegisterServer() {
[email protected]ee54aec92010-07-21 15:52:24591 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
592 BHO_CLSID | BHO_REGISTRATION;
[email protected]f7817822009-09-24 05:11:58593
[email protected]c41468f2009-11-11 20:39:18594 if (UtilIsPersistentNPAPIMarkerSet()) {
[email protected]6cc98d32010-11-27 01:54:13595 flags |= NPAPI_PLUGIN;
[email protected]ee54aec92010-07-21 15:52:24596 }
597
[email protected]59b34a72010-09-01 17:30:35598 HRESULT hr = CustomRegistration(flags, TRUE, true);
[email protected]ee54aec92010-07-21 15:52:24599 if (SUCCEEDED(hr)) {
600 SetupRunOnce();
[email protected]c41468f2009-11-11 20:39:18601 }
602
[email protected]f7817822009-09-24 05:11:58603 return hr;
604}
605
606// DllUnregisterServer - Removes entries from the system registry
607STDAPI DllUnregisterServer() {
[email protected]59b34a72010-09-01 17:30:35608 HRESULT hr = CustomRegistration(ALL, FALSE, true);
609 return hr;
610}
611
612// DllRegisterServer - Adds entries to the HKCU hive in the registry
613STDAPI DllRegisterUserServer() {
[email protected]1a5790a42010-09-10 13:46:26614 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
615 BHO_CLSID | BHO_REGISTRATION;
[email protected]59b34a72010-09-01 17:30:35616
617 if (UtilIsPersistentNPAPIMarkerSet()) {
[email protected]6cc98d32010-11-27 01:54:13618 flags |= NPAPI_PLUGIN;
[email protected]59b34a72010-09-01 17:30:35619 }
620
621 HRESULT hr = CustomRegistration(flags, TRUE, false);
622 if (SUCCEEDED(hr)) {
623 SetupRunOnce();
624 }
625
626 return hr;
627}
628
629// DllRegisterServer - Removes entries from the HKCU hive in the registry.
630STDAPI DllUnregisterUserServer() {
631 HRESULT hr = CustomRegistration(ALL, FALSE, false);
[email protected]f7817822009-09-24 05:11:58632 return hr;
633}
634
[email protected]c41468f2009-11-11 20:39:18635// Registers the NPAPI plugin and sets the persistent marker that tells us
636// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58637STDAPI RegisterNPAPIPlugin() {
638 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
639 TRUE);
[email protected]7f1a3392011-02-04 22:45:35640 if (SUCCEEDED(hr) && _AtlModule.do_system_registration_) {
[email protected]c41468f2009-11-11 20:39:18641 if (!UtilChangePersistentNPAPIMarker(true)) {
642 hr = E_FAIL;
643 }
644 }
[email protected]f7817822009-09-24 05:11:58645 return hr;
646}
647
[email protected]c41468f2009-11-11 20:39:18648// Unregisters the NPAPI plugin and clears the persistent marker that tells us
649// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58650STDAPI UnregisterNPAPIPlugin() {
651 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
652 FALSE);
[email protected]7f1a3392011-02-04 22:45:35653 if (SUCCEEDED(hr) && _AtlModule.do_system_registration_) {
[email protected]c41468f2009-11-11 20:39:18654 if (!UtilChangePersistentNPAPIMarker(false)) {
655 hr = E_FAIL;
656 }
657 }
[email protected]f7817822009-09-24 05:11:58658 return hr;
659}
[email protected]357219de2009-10-06 23:40:22660
[email protected]7f1a3392011-02-04 22:45:35661STDAPI RegisterNPAPIUserPlugin() {
662 _AtlModule.do_system_registration_ = false;
663 return RegisterNPAPIPlugin();
664}
665
666STDAPI UnregisterNPAPIUserPlugin() {
667 _AtlModule.do_system_registration_ = false;
668 return UnregisterNPAPIPlugin();
669}
670
[email protected]357219de2009-10-06 23:40:22671class SecurityDescBackup {
672 public:
673 explicit SecurityDescBackup(const std::wstring& backup_key)
674 : backup_key_name_(backup_key) {}
675 ~SecurityDescBackup() {}
676
677 // Save given security descriptor to the backup key.
678 bool SaveSecurity(const CSecurityDesc& sd) {
679 CString str;
680 if (!sd.ToString(&str))
681 return false;
682
683 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
684 KEY_READ | KEY_WRITE);
685 if (backup_key.Valid()) {
[email protected]e06f4d52011-01-19 07:28:46686 return backup_key.WriteValue(NULL, str.GetString()) == ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22687 }
688
689 return false;
690 }
691
692 // Restore security descriptor from backup key to given key name.
693 bool RestoreSecurity(const wchar_t* key_name) {
694 std::wstring sddl;
695 if (!ReadBackupKey(&sddl))
696 return false;
697
698 // Create security descriptor from string.
699 CSecurityDesc sd;
700 if (!sd.FromString(sddl.c_str()))
701 return false;
702
703 bool result = true;
704 // Restore DACL and Owner of the key from saved security descriptor.
705 CDacl dacl;
706 CSid owner;
707 sd.GetDacl(&dacl);
708 sd.GetOwner(&owner);
709
710 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
711 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
712 const_cast<SID*>(owner.GetPSID()), NULL,
713 const_cast<ACL*>(dacl.GetPACL()), NULL);
714
715 DeleteBackupKey();
716 return (error == ERROR_SUCCESS);
717 }
718
719 private:
720 // Read SDDL string from backup key
721 bool ReadBackupKey(std::wstring* sddl) {
722 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
723 if (!backup_key.Valid())
724 return false;
725
726 DWORD len = 0;
727 DWORD reg_type = REG_NONE;
[email protected]e06f4d52011-01-19 07:28:46728 if (backup_key.ReadValue(NULL, NULL, &len, &reg_type) != ERROR_SUCCESS)
[email protected]357219de2009-10-06 23:40:22729 return false;
730
731 if (reg_type != REG_SZ)
732 return false;
733
734 size_t wchar_count = 1 + len / sizeof(wchar_t);
[email protected]e06f4d52011-01-19 07:28:46735 if (backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
736 &reg_type) != ERROR_SUCCESS) {
[email protected]357219de2009-10-06 23:40:22737 return false;
738 }
739
740 return true;
741 }
742
743 void DeleteBackupKey() {
744 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
745 }
746
747 std::wstring backup_key_name_;
748};
749
750struct TokenWithPrivileges {
751 TokenWithPrivileges() {
752 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
753 token_.GetUser(&user_);
754 }
755
756 ~TokenWithPrivileges() {
757 token_.EnableDisablePrivileges(take_ownership_);
758 token_.EnableDisablePrivileges(restore_);
759 }
760
761 bool EnablePrivileges() {
762 if (take_ownership_.GetCount() == 0)
763 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
764 &take_ownership_))
765 return false;
766
767 if (restore_.GetCount() == 0)
768 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
769 return false;
770
771 return true;
772 }
773
774 const CSid& GetUser() const {
775 return user_;
776 }
777
778 private:
779 CAccessToken token_;
780 CTokenPrivileges take_ownership_;
781 CTokenPrivileges restore_;
782 CSid user_;
783};
784
[email protected]59b34a72010-09-01 17:30:35785static bool SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
[email protected]357219de2009-10-06 23:40:22786 std::wstring key_name = kInternetSettings;
787 key_name.append(L"\\Secure Mime Handlers");
[email protected]59b34a72010-09-01 17:30:35788 RegKey key(root_key, key_name.c_str(), KEY_READ | KEY_WRITE);
[email protected]357219de2009-10-06 23:40:22789 if (!key.Valid())
790 return false;
791
[email protected]e06f4d52011-01-19 07:28:46792 LONG result1 = ERROR_SUCCESS;
793 LONG result2 = ERROR_SUCCESS;
[email protected]357219de2009-10-06 23:40:22794 if (set) {
[email protected]e06f4d52011-01-19 07:28:46795 result1 = key.WriteValue(L"ChromeTab.ChromeActiveDocument", 1);
796 result2 = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1);
[email protected]357219de2009-10-06 23:40:22797 } else {
[email protected]e06f4d52011-01-19 07:28:46798 result1 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
799 result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1");
[email protected]357219de2009-10-06 23:40:22800 }
801
[email protected]e06f4d52011-01-19 07:28:46802 return (result2 == ERROR_SUCCESS) && (result2 == ERROR_SUCCESS);
[email protected]357219de2009-10-06 23:40:22803}
804
[email protected]59b34a72010-09-01 17:30:35805bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
806 if (!is_system) {
807 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
[email protected]935aa542010-10-15 01:59:15808 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
[email protected]59b34a72010-09-01 17:30:35809 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22810 }
811
812 std::wstring mime_key = kInternetSettings;
813 mime_key.append(L"\\Secure Mime Handlers");
814 std::wstring backup_key = kInternetSettings;
815 backup_key.append(L"\\__backup_SMH__");
816 std::wstring object_name = L"MACHINE\\";
817 object_name.append(mime_key);
818
819 TokenWithPrivileges token_;
820 if (!token_.EnablePrivileges())
821 return false;
822
823 // If there is a backup key - something bad happened; try to restore
824 // security on "Secure Mime Handlers" from the backup.
825 SecurityDescBackup backup(backup_key);
826 backup.RestoreSecurity(object_name.c_str());
827
828 // Read old security descriptor of the Mime key first.
829 CSecurityDesc sd;
830 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
831 return false;
832 }
833
834 backup.SaveSecurity(sd);
835 bool result = false;
836 // set new owner
837 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
838 // set new dacl
839 CDacl new_dacl;
840 sd.GetDacl(&new_dacl);
841 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
842 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
[email protected]59b34a72010-09-01 17:30:35843 result = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22844 }
845 }
846
847 backup.RestoreSecurity(object_name.c_str());
848 return result;
849}