blob: 280e0a47906dcb26654f99d41da72a519abe75ce [file] [log] [blame]
[email protected]466a9222010-06-08 01:03:161// Copyright (c) 2010 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]542bdfe2010-11-30 03:55:4716#include "base/lock.h"
[email protected]f7817822009-09-24 05:11:5817#include "base/logging.h"
[email protected]5ee34132009-11-25 21:32:2618#include "base/logging_win.h"
[email protected]f7817822009-09-24 05:11:5819#include "base/path_service.h"
[email protected]c9c077792010-08-03 14:39:4220#include "base/string_number_conversions.h"
[email protected]f7817822009-09-24 05:11:5821#include "base/string_piece.h"
22#include "base/string_util.h"
23#include "base/sys_string_conversions.h"
[email protected]2d6503982010-10-17 04:41:5424#include "base/win/registry.h"
[email protected]935aa542010-10-15 01:59:1525#include "base/win/windows_version.h"
[email protected]f7817822009-09-24 05:11:5826#include "chrome/common/chrome_constants.h"
[email protected]02ea78a2010-07-15 16:52:2827#include "chrome/common/chrome_switches.h"
28#include "chrome/installer/util/google_update_settings.h"
[email protected]f7817822009-09-24 05:11:5829#include "chrome_frame/bho.h"
[email protected]ea9ed97d2010-01-05 19:16:2330#include "chrome_frame/chrome_active_document.h"
31#include "chrome_frame/chrome_frame_activex.h"
[email protected]f7817822009-09-24 05:11:5832#include "chrome_frame/chrome_frame_automation.h"
[email protected]53556e12009-10-15 21:49:2233#include "chrome_frame/chrome_frame_reporting.h"
[email protected]79b663c2010-05-28 17:27:1734#include "chrome_frame/chrome_launcher_utils.h"
[email protected]ea9ed97d2010-01-05 19:16:2335#include "chrome_frame/chrome_protocol.h"
[email protected]c6352e92010-12-03 01:57:4736#include "chrome_frame/dll_redirector.h"
37#include "chrome_frame/exception_barrier.h"
[email protected]f7817822009-09-24 05:11:5838#include "chrome_frame/resource.h"
39#include "chrome_frame/utils.h"
[email protected]cebd4132010-03-25 15:34:2240#include "googleurl/src/url_util.h"
[email protected]c6352e92010-12-03 01:57:4741#include "grit/chrome_frame_resources.h"
[email protected]cebd4132010-03-25 15:34:2242
[email protected]2d6503982010-10-17 04:41:5443using base::win::RegKey;
44
[email protected]cebd4132010-03-25 15:34:2245namespace {
46// This function has the side effect of initializing an unprotected
47// vector pointer inside GoogleUrl. If this is called during DLL loading,
[email protected]59b34a72010-09-01 17:30:3548// it has the effect of avoiding an initialization race on that pointer.
[email protected]cebd4132010-03-25 15:34:2249// TODO(siggi): fix GoogleUrl.
50void InitGoogleUrl() {
51 static const char kDummyUrl[] = "http://www.google.com";
52
53 url_util::IsStandard(kDummyUrl,
54 url_parse::MakeRange(0, arraysize(kDummyUrl)));
55}
[email protected]cebd4132010-03-25 15:34:2256}
[email protected]f7817822009-09-24 05:11:5857
[email protected]f7817822009-09-24 05:11:5858static const wchar_t kBhoRegistryPath[] =
59 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
60 L"\\Browser Helper Objects";
61
[email protected]357219de2009-10-06 23:40:2262const wchar_t kInternetSettings[] =
63 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
64
[email protected]552fb6012010-02-03 17:24:2965const wchar_t kProtocolHandlers[] =
66 L"Software\\Classes\\Protocols\\Handler";
67
[email protected]02ea78a2010-07-15 16:52:2868const wchar_t kRunOnce[] =
69 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
70
[email protected]c5c6c8c2010-09-07 13:57:2171const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
72
73const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
74
75// Window class and window names.
76// TODO(robertshield): These and other constants need to be refactored into
77// a common chrome_frame_constants.h|cc and built into a separate lib
78// (either chrome_frame_utils or make another one).
79const wchar_t kChromeFrameHelperWindowClassName[] =
80 L"ChromeFrameHelperWindowClass";
81const wchar_t kChromeFrameHelperWindowName[] =
82 L"ChromeFrameHelperWindowName";
[email protected]f7817822009-09-24 05:11:5883
[email protected]5ee34132009-11-25 21:32:2684// {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
85static const GUID kChromeFrameProvider =
86 { 0x562bfc3, 0x2550, 0x45b4,
87 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
88
[email protected]ea9ed97d2010-01-05 19:16:2389// Object entries go here instead of with each object, so that we can move
90// the objects to a lib. Also reduces magic.
91OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
92OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
93OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
94OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)
[email protected]5ee34132009-11-25 21:32:2695
[email protected]8adbf7e52010-04-14 20:03:2396
97// See comments in DllGetClassObject.
[email protected]52749842010-05-07 21:34:4198LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
[email protected]8adbf7e52010-04-14 20:03:2399
[email protected]6bdc0c02010-07-20 14:52:13100class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
[email protected]f7817822009-09-24 05:11:58101 public:
[email protected]6bdc0c02010-07-20 14:52:13102 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
[email protected]f7817822009-09-24 05:11:58103
[email protected]59b34a72010-09-01 17:30:35104 ChromeTabModule() : do_system_registration_(true) {}
105
[email protected]f7817822009-09-24 05:11:58106 DECLARE_LIBID(LIBID_ChromeTabLib)
107 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
108 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
109
110 // Override to add our SYSTIME binary value to registry scripts.
111 // See chrome_frame_activex.rgs for usage.
112 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
113 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
114
115 if (SUCCEEDED(hr)) {
116 SYSTEMTIME local_time;
117 ::GetSystemTime(&local_time);
[email protected]c9c077792010-08-03 14:39:42118 std::string hex(base::HexEncode(&local_time, sizeof(local_time)));
[email protected]f7817822009-09-24 05:11:58119 base::StringPiece sp_hex(hex);
120 hr = registrar->AddReplacement(L"SYSTIME",
121 base::SysNativeMBToWide(sp_hex).c_str());
122 DCHECK(SUCCEEDED(hr));
123 }
124
125 if (SUCCEEDED(hr)) {
[email protected]66ff7352009-10-15 05:09:50126 FilePath app_path =
127 chrome_launcher::GetChromeExecutablePath().DirName();
128 hr = registrar->AddReplacement(L"CHROME_APPPATH",
129 app_path.value().c_str());
[email protected]f7817822009-09-24 05:11:58130 DCHECK(SUCCEEDED(hr));
131 }
132
133 if (SUCCEEDED(hr)) {
134 hr = registrar->AddReplacement(L"CHROME_APPNAME",
135 chrome::kBrowserProcessExecutableName);
136 DCHECK(SUCCEEDED(hr));
137
138 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
139 scoped_ptr<FileVersionInfo> module_version_info(
140 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
141 DCHECK(module_version_info != NULL);
142 std::wstring file_version(module_version_info->file_version());
143 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
144 DCHECK(SUCCEEDED(hr));
145 }
146
147 if (SUCCEEDED(hr)) {
148 // Add the directory of chrome_launcher.exe. This will be the same
149 // as the directory for the current DLL.
150 std::wstring module_dir;
151 FilePath module_path;
152 if (PathService::Get(base::FILE_MODULE, &module_path)) {
[email protected]466a9222010-06-08 01:03:16153 module_dir = module_path.DirName().value();
[email protected]f7817822009-09-24 05:11:58154 } else {
155 NOTREACHED();
156 }
157 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
158 module_dir.c_str());
159 DCHECK(SUCCEEDED(hr));
160 }
161
162 if (SUCCEEDED(hr)) {
163 // Add the filename of chrome_launcher.exe
164 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
165 chrome_launcher::kLauncherExeBaseName);
166 DCHECK(SUCCEEDED(hr));
167 }
168
[email protected]59b34a72010-09-01 17:30:35169 if (SUCCEEDED(hr)) {
170 // Add the registry hive to use.
171 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter
172 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a
173 // few components that are registered by calling their
174 // static T::UpdateRegistry() methods directly, which doesn't allow
175 // pMapEntries to be passed through :-(
176 if (do_system_registration_) {
177 hr = registrar->AddReplacement(L"HIVE", L"HKLM");
178 } else {
179 hr = registrar->AddReplacement(L"HIVE", L"HKCU");
180 }
181 DCHECK(SUCCEEDED(hr));
182 }
183
[email protected]f7817822009-09-24 05:11:58184 return hr;
185 }
[email protected]59b34a72010-09-01 17:30:35186
187 // See comments in AddCommonRGSReplacements
188 bool do_system_registration_;
[email protected]f7817822009-09-24 05:11:58189};
190
191ChromeTabModule _AtlModule;
192
193base::AtExitManager* g_exit_manager = NULL;
[email protected]59b34a72010-09-01 17:30:35194bool RegisterSecuredMimeHandler(bool enable, bool is_system); // forward
[email protected]f7817822009-09-24 05:11:58195
196// DLL Entry Point
197extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
198 DWORD reason,
199 LPVOID reserved) {
200 UNREFERENCED_PARAMETER(instance);
201 if (reason == DLL_PROCESS_ATTACH) {
202#ifndef NDEBUG
203 // Silence traces from the ATL registrar to reduce the log noise.
204 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
205 ATLTRACESTATUS_DISABLED);
206#endif
[email protected]cebd4132010-03-25 15:34:22207 InitGoogleUrl();
208
[email protected]c41468f2009-11-11 20:39:18209 g_exit_manager = new base::AtExitManager();
[email protected]74d1eec2009-11-04 22:18:57210 CommandLine::Init(0, NULL);
[email protected]53556e12009-10-15 21:49:22211 InitializeCrashReporting();
[email protected]7c10f7552011-01-11 01:03:36212 logging::InitLogging(
213 NULL,
214 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
215 logging::LOCK_LOG_FILE,
216 logging::DELETE_OLD_LOG_FILE,
217 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
[email protected]52749842010-05-07 21:34:41218
[email protected]687b9602010-12-08 10:43:08219 DllRedirector* dll_redirector = DllRedirector::GetInstance();
[email protected]8cc41942010-11-05 19:16:07220 DCHECK(dll_redirector);
221
222 if (!dll_redirector->RegisterAsFirstCFModule()) {
223 // Someone else was here first, try and get a pointer to their
224 // DllGetClassObject export:
225 g_dll_get_class_object_redir_ptr =
226 dll_redirector->GetDllGetClassObjectPtr();
227 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
228 << "Found CF module with no DllGetClassObject export.";
[email protected]52749842010-05-07 21:34:41229 }
230
[email protected]5ee34132009-11-25 21:32:26231 // Enable ETW logging.
232 logging::LogEventProvider::Initialize(kChromeFrameProvider);
[email protected]f7817822009-09-24 05:11:58233 } else if (reason == DLL_PROCESS_DETACH) {
[email protected]687b9602010-12-08 10:43:08234 DllRedirector* dll_redirector = DllRedirector::GetInstance();
[email protected]8cc41942010-11-05 19:16:07235 DCHECK(dll_redirector);
236
237 dll_redirector->UnregisterAsFirstCFModule();
[email protected]f7817822009-09-24 05:11:58238 g_patch_helper.UnpatchIfNeeded();
239 delete g_exit_manager;
240 g_exit_manager = NULL;
241 ShutdownCrashReporting();
242 }
243 return _AtlModule.DllMain(reason, reserved);
244}
245
246#ifdef _MANAGED
247#pragma managed(pop)
248#endif
249
[email protected]f7817822009-09-24 05:11:58250HRESULT RefreshElevationPolicy() {
251 const wchar_t kIEFrameDll[] = L"ieframe.dll";
252 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
253 HRESULT hr = E_NOTIMPL;
[email protected]1f08d682010-05-19 18:48:31254
255 // Stick an SEH in the chain to prevent the VEH from picking up on first
256 // chance exceptions caused by loading ieframe.dll. Use the vanilla
257 // ExceptionBarrier to report any exceptions that do make their way to us
258 // though.
259 ExceptionBarrier barrier;
260
[email protected]f7817822009-09-24 05:11:58261 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
262 if (ieframe_module) {
263 typedef HRESULT (__stdcall *IERefreshPolicy)();
264 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
265 GetProcAddress(ieframe_module, kIERefreshPolicy));
266
267 if (ie_refresh_policy) {
268 hr = ie_refresh_policy();
269 } else {
270 hr = HRESULT_FROM_WIN32(GetLastError());
271 }
[email protected]357219de2009-10-06 23:40:22272
[email protected]f7817822009-09-24 05:11:58273 FreeLibrary(ieframe_module);
274 } else {
275 hr = HRESULT_FROM_WIN32(GetLastError());
276 }
277
278 return hr;
279}
280
[email protected]02ea78a2010-07-15 16:52:28281// Experimental boot prefetch optimization for Chrome Frame
282//
283// If chrome is warmed up during a single reboot, it gets paged
284// in for subsequent reboots and the cold startup times essentially
285// look like warm times thereafter! The 'warm up' is done by
286// setting up a 'RunOnce' key during DLLRegisterServer of
287// npchrome_frame.dll.
288//
289// This works because chrome prefetch becomes part of boot
290// prefetch file ntosboot-b00dfaad.pf and paged in on subsequent
291// reboots. As long as the sytem does not undergo significant
292// memory pressure those pages remain in memory and we get pretty
293// amazing startup times, down to about 300 ms from 1200 ms
294//
295// The downside is:
296// - Whether chrome frame is used or not, there's a read penalty
297// (1200-300 =) 900 ms for every boot.
298// - Heavy system memory usage after reboot will nullify the benefits
299// but the user will still pay the cost.
300// - Overall the time saved will always be less than total time spent
301// paging in chrome
302// - We are not sure when the chrome 'warm up' will age out from the
303// boot prefetch file.
304//
305// The idea here is to try this out on chrome frame dev channel
306// and see if it produces a significant drift in startup numbers.
307HRESULT SetupRunOnce() {
[email protected]7fc3e6922010-11-18 17:56:54308 HRESULT result = E_FAIL;
[email protected]02ea78a2010-07-15 16:52:28309
310 std::wstring channel_name;
[email protected]7fc3e6922010-11-18 17:56:54311 if (base::win::GetVersion() < base::win::VERSION_VISTA &&
312 GoogleUpdateSettings::GetChromeChannel(true, &channel_name)) {
313 std::transform(channel_name.begin(), channel_name.end(),
314 channel_name.begin(), tolower);
315 // Use this only for the dev channel and CEEE channels.
316 if (channel_name.find(L"dev") != std::wstring::npos ||
317 channel_name.find(L"ceee") != std::wstring::npos) {
[email protected]542bdfe2010-11-30 03:55:47318
[email protected]7fc3e6922010-11-18 17:56:54319 HKEY hive = HKEY_CURRENT_USER;
320 if (IsSystemProcess()) {
321 // For system installs, our updates will be running as SYSTEM which
322 // makes writing to a RunOnce key under HKCU not so terribly useful.
323 hive = HKEY_LOCAL_MACHINE;
324 }
[email protected]74ecb5a42010-09-03 00:44:35325
[email protected]7fc3e6922010-11-18 17:56:54326 RegKey run_once;
327 if (run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE)) {
328 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);
332 if (run_once.WriteValue(L"A",
333 run_once_cmd.command_line_string().c_str())) {
334 result = S_OK;
335 }
336 }
337 } else {
338 result = S_FALSE;
339 }
340 } else {
341 // We're on a non-XP version of Windows or on a stable channel. Nothing
342 // needs doing.
343 result = S_FALSE;
[email protected]552fb6012010-02-03 17:24:29344 }
345
[email protected]7fc3e6922010-11-18 17:56:54346 return result;
[email protected]552fb6012010-02-03 17:24:29347}
348
[email protected]c5c6c8c2010-09-07 13:57:21349// Helper method called for user-level installs where we don't have admin
350// permissions. Starts up the long running process and registers it to get it
351// started at next boot.
352void SetupUserLevelHelper() {
353 // Remove existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50354 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21355
356 // Build the chrome_frame_helper command line.
357 FilePath module_path;
358 FilePath helper_path;
359 if (PathService::Get(base::FILE_MODULE, &module_path)) {
360 module_path = module_path.DirName();
361 helper_path = module_path.Append(kChromeFrameHelperExe);
362 if (!file_util::PathExists(helper_path)) {
363 // If we can't find the helper in the current directory, try looking
364 // one up (this is the layout in the build output folder).
365 module_path = module_path.DirName();
366 helper_path = module_path.Append(kChromeFrameHelperExe);
367 DCHECK(file_util::PathExists(helper_path)) <<
368 "Could not find chrome_frame_helper.exe.";
369 }
370 } else {
371 NOTREACHED();
372 }
373
374 // Find window handle of existing instance.
375 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName,
376 kChromeFrameHelperWindowName);
377
378 if (file_util::PathExists(helper_path)) {
379 // Add new run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50380 base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName,
[email protected]c5c6c8c2010-09-07 13:57:21381 helper_path.value());
382
383 // Start new instance.
384 bool launched = base::LaunchApp(helper_path.value(), false, true, NULL);
385 if (!launched) {
386 NOTREACHED();
387 LOG(ERROR) << "Could not launch helper process.";
388 }
389
390 // Kill old instance using window handle.
391 if (IsWindow(old_window)) {
392 BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0);
393 if (!result) {
394 LOG(ERROR) << "Failed to post close message to old helper process: "
395 << GetLastError();
396 }
397 }
398 }
399}
400
401
[email protected]f7817822009-09-24 05:11:58402// Used to determine whether the DLL can be unloaded by OLE
403STDAPI DllCanUnloadNow() {
404 return _AtlModule.DllCanUnloadNow();
405}
406
407// Returns a class factory to create an object of the requested type
408STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
[email protected]52749842010-05-07 21:34:41409 // If we found another module present when we were loaded, then delegate to
410 // that:
411 if (g_dll_get_class_object_redir_ptr) {
412 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
[email protected]8adbf7e52010-04-14 20:03:23413 }
[email protected]ee54aec92010-07-21 15:52:24414
415 // Enable sniffing and switching only if asked for BHO
416 // (we use BHO to get loaded in IE).
417 if (rclsid == CLSID_ChromeFrameBHO) {
418 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
419 }
420
421 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
[email protected]f7817822009-09-24 05:11:58422}
423
[email protected]6a8515e42010-12-16 19:38:52424const wchar_t kPostPlatformUAKey[] =
425 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
426 L"User Agent\\Post Platform";
427const wchar_t kChromeFramePrefix[] = L"chromeframe/";
428
429// To delete the user agent, set value to NULL.
430// The is_system parameter indicates whether this is a per machine or a per
431// user installation.
432HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) {
433 HRESULT hr = E_FAIL;
434 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
435
436 RegKey ua_key;
[email protected]45b716b2011-01-14 18:43:53437 if (ua_key.Create(parent_hive, kPostPlatformUAKey, KEY_READ | KEY_WRITE)) {
438 // 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)))
492 flags |= (TYPELIB |GCF_PROTOCOL);
493
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]0f5945b12010-08-11 21:03:30514 // TODO(amit): Move elevation policy registration from ActiveX rgs
515 // into a separate rgs.
516 RefreshElevationPolicy();
[email protected]ee54aec92010-07-21 15:52:24517 }
518
519 if ((hr == S_OK) && (flags & GCF_PROTOCOL)) {
520 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg);
521 }
522
523 if ((hr == S_OK) && (flags & BHO_CLSID)) {
524 hr = Bho::UpdateRegistry(reg);
525 }
526
[email protected]c5c6c8c2010-09-07 13:57:21527 if ((hr == S_OK) && (flags & BHO_REGISTRATION)) {
528 if (is_system) {
529 _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg);
530 } else {
531 if (reg) {
532 // Setup the long running process:
533 SetupUserLevelHelper();
534 } else {
535 // Unschedule the user-level helper. Note that we don't kill it here so
536 // that during updates we don't have a time window with no running
537 // helper. Uninstalls and updates will explicitly kill the helper from
538 // within the installer. Unregister existing run-at-startup entry.
[email protected]a8e20582010-12-31 17:18:50539 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName);
[email protected]c5c6c8c2010-09-07 13:57:21540 }
541 }
[email protected]ee54aec92010-07-21 15:52:24542 }
543
544 if ((hr == S_OK) && (flags & TYPELIB)) {
[email protected]59b34a72010-09-01 17:30:35545 hr = (reg)?
546 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system) :
547 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, NULL, !is_system);
[email protected]ee54aec92010-07-21 15:52:24548 }
549
550 if ((hr == S_OK) && (flags & NPAPI_PLUGIN)) {
551 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg);
552 }
553
554 if (hr == S_OK) {
555 hr = _AtlModule.UpdateRegistryAppId(reg);
556 }
557
[email protected]6a8515e42010-12-16 19:38:52558 if (hr == S_OK) {
559 if (reg) {
560 hr = SetChromeFrameUA(is_system, L"1");
561 } else {
562 hr = SetChromeFrameUA(is_system, NULL);
563 }
564 }
[email protected]ee54aec92010-07-21 15:52:24565 return hr;
566}
567
568
569
[email protected]f7817822009-09-24 05:11:58570// DllRegisterServer - Adds entries to the system registry
571STDAPI DllRegisterServer() {
[email protected]ee54aec92010-07-21 15:52:24572 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
573 BHO_CLSID | BHO_REGISTRATION;
[email protected]f7817822009-09-24 05:11:58574
[email protected]c41468f2009-11-11 20:39:18575 if (UtilIsPersistentNPAPIMarkerSet()) {
[email protected]6cc98d32010-11-27 01:54:13576 flags |= NPAPI_PLUGIN;
[email protected]ee54aec92010-07-21 15:52:24577 }
578
[email protected]59b34a72010-09-01 17:30:35579 HRESULT hr = CustomRegistration(flags, TRUE, true);
[email protected]ee54aec92010-07-21 15:52:24580 if (SUCCEEDED(hr)) {
581 SetupRunOnce();
[email protected]c41468f2009-11-11 20:39:18582 }
583
[email protected]f7817822009-09-24 05:11:58584 return hr;
585}
586
587// DllUnregisterServer - Removes entries from the system registry
588STDAPI DllUnregisterServer() {
[email protected]59b34a72010-09-01 17:30:35589 HRESULT hr = CustomRegistration(ALL, FALSE, true);
590 return hr;
591}
592
593// DllRegisterServer - Adds entries to the HKCU hive in the registry
594STDAPI DllRegisterUserServer() {
[email protected]1a5790a42010-09-10 13:46:26595 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
596 BHO_CLSID | BHO_REGISTRATION;
[email protected]59b34a72010-09-01 17:30:35597
598 if (UtilIsPersistentNPAPIMarkerSet()) {
[email protected]6cc98d32010-11-27 01:54:13599 flags |= NPAPI_PLUGIN;
[email protected]59b34a72010-09-01 17:30:35600 }
601
602 HRESULT hr = CustomRegistration(flags, TRUE, false);
603 if (SUCCEEDED(hr)) {
604 SetupRunOnce();
605 }
606
607 return hr;
608}
609
610// DllRegisterServer - Removes entries from the HKCU hive in the registry.
611STDAPI DllUnregisterUserServer() {
612 HRESULT hr = CustomRegistration(ALL, FALSE, false);
[email protected]f7817822009-09-24 05:11:58613 return hr;
614}
615
[email protected]c41468f2009-11-11 20:39:18616// Registers the NPAPI plugin and sets the persistent marker that tells us
617// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58618STDAPI RegisterNPAPIPlugin() {
619 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
620 TRUE);
[email protected]c41468f2009-11-11 20:39:18621 if (SUCCEEDED(hr)) {
622 if (!UtilChangePersistentNPAPIMarker(true)) {
623 hr = E_FAIL;
624 }
625 }
[email protected]f7817822009-09-24 05:11:58626 return hr;
627}
628
[email protected]c41468f2009-11-11 20:39:18629// Unregisters the NPAPI plugin and clears the persistent marker that tells us
630// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58631STDAPI UnregisterNPAPIPlugin() {
632 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
633 FALSE);
[email protected]c41468f2009-11-11 20:39:18634 if (SUCCEEDED(hr)) {
635 if (!UtilChangePersistentNPAPIMarker(false)) {
636 hr = E_FAIL;
637 }
638 }
[email protected]f7817822009-09-24 05:11:58639 return hr;
640}
[email protected]357219de2009-10-06 23:40:22641
642class SecurityDescBackup {
643 public:
644 explicit SecurityDescBackup(const std::wstring& backup_key)
645 : backup_key_name_(backup_key) {}
646 ~SecurityDescBackup() {}
647
648 // Save given security descriptor to the backup key.
649 bool SaveSecurity(const CSecurityDesc& sd) {
650 CString str;
651 if (!sd.ToString(&str))
652 return false;
653
654 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
655 KEY_READ | KEY_WRITE);
656 if (backup_key.Valid()) {
657 return backup_key.WriteValue(NULL, str.GetString());
658 }
659
660 return false;
661 }
662
663 // Restore security descriptor from backup key to given key name.
664 bool RestoreSecurity(const wchar_t* key_name) {
665 std::wstring sddl;
666 if (!ReadBackupKey(&sddl))
667 return false;
668
669 // Create security descriptor from string.
670 CSecurityDesc sd;
671 if (!sd.FromString(sddl.c_str()))
672 return false;
673
674 bool result = true;
675 // Restore DACL and Owner of the key from saved security descriptor.
676 CDacl dacl;
677 CSid owner;
678 sd.GetDacl(&dacl);
679 sd.GetOwner(&owner);
680
681 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
682 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
683 const_cast<SID*>(owner.GetPSID()), NULL,
684 const_cast<ACL*>(dacl.GetPACL()), NULL);
685
686 DeleteBackupKey();
687 return (error == ERROR_SUCCESS);
688 }
689
690 private:
691 // Read SDDL string from backup key
692 bool ReadBackupKey(std::wstring* sddl) {
693 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
694 if (!backup_key.Valid())
695 return false;
696
697 DWORD len = 0;
698 DWORD reg_type = REG_NONE;
699 if (!backup_key.ReadValue(NULL, NULL, &len, &reg_type))
700 return false;
701
702 if (reg_type != REG_SZ)
703 return false;
704
705 size_t wchar_count = 1 + len / sizeof(wchar_t);
706 if (!backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
707 &reg_type)) {
708 return false;
709 }
710
711 return true;
712 }
713
714 void DeleteBackupKey() {
715 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
716 }
717
718 std::wstring backup_key_name_;
719};
720
721struct TokenWithPrivileges {
722 TokenWithPrivileges() {
723 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
724 token_.GetUser(&user_);
725 }
726
727 ~TokenWithPrivileges() {
728 token_.EnableDisablePrivileges(take_ownership_);
729 token_.EnableDisablePrivileges(restore_);
730 }
731
732 bool EnablePrivileges() {
733 if (take_ownership_.GetCount() == 0)
734 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
735 &take_ownership_))
736 return false;
737
738 if (restore_.GetCount() == 0)
739 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
740 return false;
741
742 return true;
743 }
744
745 const CSid& GetUser() const {
746 return user_;
747 }
748
749 private:
750 CAccessToken token_;
751 CTokenPrivileges take_ownership_;
752 CTokenPrivileges restore_;
753 CSid user_;
754};
755
[email protected]59b34a72010-09-01 17:30:35756static bool SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) {
[email protected]357219de2009-10-06 23:40:22757 std::wstring key_name = kInternetSettings;
758 key_name.append(L"\\Secure Mime Handlers");
[email protected]59b34a72010-09-01 17:30:35759 RegKey key(root_key, key_name.c_str(), KEY_READ | KEY_WRITE);
[email protected]357219de2009-10-06 23:40:22760 if (!key.Valid())
761 return false;
762
763 bool result;
764 if (set) {
765 result = key.WriteValue(L"ChromeTab.ChromeActiveDocument", 1);
766 result = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1) && result;
767 } else {
768 result = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
769 result = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1") && result;
770 }
771
772 return result;
773}
774
[email protected]59b34a72010-09-01 17:30:35775bool RegisterSecuredMimeHandler(bool enable, bool is_system) {
776 if (!is_system) {
777 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
[email protected]935aa542010-10-15 01:59:15778 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
[email protected]59b34a72010-09-01 17:30:35779 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22780 }
781
782 std::wstring mime_key = kInternetSettings;
783 mime_key.append(L"\\Secure Mime Handlers");
784 std::wstring backup_key = kInternetSettings;
785 backup_key.append(L"\\__backup_SMH__");
786 std::wstring object_name = L"MACHINE\\";
787 object_name.append(mime_key);
788
789 TokenWithPrivileges token_;
790 if (!token_.EnablePrivileges())
791 return false;
792
793 // If there is a backup key - something bad happened; try to restore
794 // security on "Secure Mime Handlers" from the backup.
795 SecurityDescBackup backup(backup_key);
796 backup.RestoreSecurity(object_name.c_str());
797
798 // Read old security descriptor of the Mime key first.
799 CSecurityDesc sd;
800 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
801 return false;
802 }
803
804 backup.SaveSecurity(sd);
805 bool result = false;
806 // set new owner
807 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
808 // set new dacl
809 CDacl new_dacl;
810 sd.GetDacl(&new_dacl);
811 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
812 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
[email protected]59b34a72010-09-01 17:30:35813 result = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
[email protected]357219de2009-10-06 23:40:22814 }
815 }
816
817 backup.RestoreSecurity(object_name.c_str());
818 return result;
819}