blob: 5165d2c9e7aa823d48ea850777fabff20d99e6d5 [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]8adbf7e52010-04-14 20:03:2316#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"
20#include "base/registry.h"
21#include "base/string_piece.h"
22#include "base/string_util.h"
23#include "base/sys_string_conversions.h"
[email protected]357219de2009-10-06 23:40:2224#include "base/win_util.h"
[email protected]f7817822009-09-24 05:11:5825#include "chrome/common/chrome_constants.h"
26#include "grit/chrome_frame_resources.h"
27#include "chrome_frame/bho.h"
[email protected]ea9ed97d2010-01-05 19:16:2328#include "chrome_frame/chrome_active_document.h"
29#include "chrome_frame/chrome_frame_activex.h"
[email protected]f7817822009-09-24 05:11:5830#include "chrome_frame/chrome_frame_automation.h"
[email protected]1f08d682010-05-19 18:48:3131#include "chrome_frame/exception_barrier.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]8adbf7e52010-04-14 20:03:2335#include "chrome_frame/module_utils.h"
[email protected]f7817822009-09-24 05:11:5836#include "chrome_frame/resource.h"
37#include "chrome_frame/utils.h"
[email protected]cebd4132010-03-25 15:34:2238#include "googleurl/src/url_util.h"
39
40namespace {
41// This function has the side effect of initializing an unprotected
42// vector pointer inside GoogleUrl. If this is called during DLL loading,
43// it has the effect of avoiding an initializiation race on that pointer.
44// TODO(siggi): fix GoogleUrl.
45void InitGoogleUrl() {
46 static const char kDummyUrl[] = "http://www.google.com";
47
48 url_util::IsStandard(kDummyUrl,
49 url_parse::MakeRange(0, arraysize(kDummyUrl)));
50}
[email protected]cebd4132010-03-25 15:34:2251}
[email protected]f7817822009-09-24 05:11:5852
[email protected]f7817822009-09-24 05:11:5853static const wchar_t kBhoRegistryPath[] =
54 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
55 L"\\Browser Helper Objects";
56
[email protected]357219de2009-10-06 23:40:2257const wchar_t kInternetSettings[] =
58 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
59
[email protected]552fb6012010-02-03 17:24:2960const wchar_t kProtocolHandlers[] =
61 L"Software\\Classes\\Protocols\\Handler";
62
[email protected]f7817822009-09-24 05:11:5863const wchar_t kBhoNoLoadExplorerValue[] = L"NoExplorer";
64
[email protected]5ee34132009-11-25 21:32:2665// {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
66static const GUID kChromeFrameProvider =
67 { 0x562bfc3, 0x2550, 0x45b4,
68 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
69
[email protected]ea9ed97d2010-01-05 19:16:2370// Object entries go here instead of with each object, so that we can move
71// the objects to a lib. Also reduces magic.
72OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
73OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
74OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
75OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)
[email protected]5ee34132009-11-25 21:32:2676
[email protected]8adbf7e52010-04-14 20:03:2377
78// See comments in DllGetClassObject.
[email protected]52749842010-05-07 21:34:4179LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
[email protected]8adbf7e52010-04-14 20:03:2380
[email protected]f7817822009-09-24 05:11:5881class ChromeTabModule
82 : public AtlPerUserModule<CAtlDllModuleT<ChromeTabModule> > {
83 public:
84 typedef AtlPerUserModule<CAtlDllModuleT<ChromeTabModule> > ParentClass;
85
86 DECLARE_LIBID(LIBID_ChromeTabLib)
87 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
88 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
89
90 // Override to add our SYSTIME binary value to registry scripts.
91 // See chrome_frame_activex.rgs for usage.
92 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
93 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
94
95 if (SUCCEEDED(hr)) {
96 SYSTEMTIME local_time;
97 ::GetSystemTime(&local_time);
98 std::string hex(HexEncode(&local_time, sizeof(local_time)));
99 base::StringPiece sp_hex(hex);
100 hr = registrar->AddReplacement(L"SYSTIME",
101 base::SysNativeMBToWide(sp_hex).c_str());
102 DCHECK(SUCCEEDED(hr));
103 }
104
105 if (SUCCEEDED(hr)) {
[email protected]66ff7352009-10-15 05:09:50106 FilePath app_path =
107 chrome_launcher::GetChromeExecutablePath().DirName();
108 hr = registrar->AddReplacement(L"CHROME_APPPATH",
109 app_path.value().c_str());
[email protected]f7817822009-09-24 05:11:58110 DCHECK(SUCCEEDED(hr));
111 }
112
113 if (SUCCEEDED(hr)) {
114 hr = registrar->AddReplacement(L"CHROME_APPNAME",
115 chrome::kBrowserProcessExecutableName);
116 DCHECK(SUCCEEDED(hr));
117
118 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources.
119 scoped_ptr<FileVersionInfo> module_version_info(
120 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
121 DCHECK(module_version_info != NULL);
122 std::wstring file_version(module_version_info->file_version());
123 hr = registrar->AddReplacement(L"VERSION", file_version.c_str());
124 DCHECK(SUCCEEDED(hr));
125 }
126
127 if (SUCCEEDED(hr)) {
128 // Add the directory of chrome_launcher.exe. This will be the same
129 // as the directory for the current DLL.
130 std::wstring module_dir;
131 FilePath module_path;
132 if (PathService::Get(base::FILE_MODULE, &module_path)) {
[email protected]466a9222010-06-08 01:03:16133 module_dir = module_path.DirName().value();
[email protected]f7817822009-09-24 05:11:58134 } else {
135 NOTREACHED();
136 }
137 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH",
138 module_dir.c_str());
139 DCHECK(SUCCEEDED(hr));
140 }
141
142 if (SUCCEEDED(hr)) {
143 // Add the filename of chrome_launcher.exe
144 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME",
145 chrome_launcher::kLauncherExeBaseName);
146 DCHECK(SUCCEEDED(hr));
147 }
148
149 return hr;
150 }
151};
152
153ChromeTabModule _AtlModule;
154
155base::AtExitManager* g_exit_manager = NULL;
[email protected]357219de2009-10-06 23:40:22156bool RegisterSecuredMimeHandler(bool enable); // forward
[email protected]f7817822009-09-24 05:11:58157
158// DLL Entry Point
159extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
160 DWORD reason,
161 LPVOID reserved) {
162 UNREFERENCED_PARAMETER(instance);
163 if (reason == DLL_PROCESS_ATTACH) {
164#ifndef NDEBUG
165 // Silence traces from the ATL registrar to reduce the log noise.
166 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
167 ATLTRACESTATUS_DISABLED);
168#endif
[email protected]cebd4132010-03-25 15:34:22169 InitGoogleUrl();
170
[email protected]c41468f2009-11-11 20:39:18171 g_exit_manager = new base::AtExitManager();
[email protected]74d1eec2009-11-04 22:18:57172 CommandLine::Init(0, NULL);
[email protected]53556e12009-10-15 21:49:22173 InitializeCrashReporting();
[email protected]f7817822009-09-24 05:11:58174 logging::InitLogging(NULL, logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
175 logging::LOCK_LOG_FILE, logging::DELETE_OLD_LOG_FILE);
[email protected]52749842010-05-07 21:34:41176
177 if (!DllRedirector::RegisterAsFirstCFModule()) {
178 // We are not the first ones in, get the module who registered first.
179 HMODULE original_module = DllRedirector::GetFirstCFModule();
180 DCHECK(original_module != NULL)
181 << "Could not get first CF module handle.";
182 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
183 if (original_module != this_module) {
184 // Someone else was here first, try and get a pointer to their
185 // DllGetClassObject export:
186 g_dll_get_class_object_redir_ptr =
187 DllRedirector::GetDllGetClassObjectPtr(original_module);
188 DCHECK(g_dll_get_class_object_redir_ptr != NULL)
189 << "Found CF module with no DllGetClassObject export.";
190 }
191 }
192
[email protected]5ee34132009-11-25 21:32:26193 // Enable ETW logging.
194 logging::LogEventProvider::Initialize(kChromeFrameProvider);
[email protected]f7817822009-09-24 05:11:58195 } else if (reason == DLL_PROCESS_DETACH) {
[email protected]52749842010-05-07 21:34:41196 DllRedirector::UnregisterAsFirstCFModule();
[email protected]f7817822009-09-24 05:11:58197 g_patch_helper.UnpatchIfNeeded();
198 delete g_exit_manager;
199 g_exit_manager = NULL;
200 ShutdownCrashReporting();
201 }
202 return _AtlModule.DllMain(reason, reserved);
203}
204
205#ifdef _MANAGED
206#pragma managed(pop)
207#endif
208
209const wchar_t kPostPlatformUAKey[] =
210 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
211 L"User Agent\\Post Platform";
212const wchar_t kClockUserAgent[] = L"chromeframe";
213
214// To delete the clock user agent, set value to NULL.
[email protected]3f55e872009-10-17 04:48:37215// TODO(tommi): Remove this method when it's no longer used.
[email protected]f7817822009-09-24 05:11:58216HRESULT SetClockUserAgent(const wchar_t* value) {
217 HRESULT hr;
218 RegKey ua_key;
[email protected]2884a002009-10-13 14:56:21219 if (ua_key.Create(HKEY_LOCAL_MACHINE, kPostPlatformUAKey, KEY_WRITE)) {
[email protected]f7817822009-09-24 05:11:58220 if (value) {
221 ua_key.WriteValue(kClockUserAgent, value);
222 } else {
223 ua_key.DeleteValue(kClockUserAgent);
224 }
225 hr = S_OK;
226 } else {
227 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey;
228 hr = E_UNEXPECTED;
229 }
230
231 return hr;
232}
233
234HRESULT RefreshElevationPolicy() {
235 const wchar_t kIEFrameDll[] = L"ieframe.dll";
236 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
237 HRESULT hr = E_NOTIMPL;
[email protected]1f08d682010-05-19 18:48:31238
239 // Stick an SEH in the chain to prevent the VEH from picking up on first
240 // chance exceptions caused by loading ieframe.dll. Use the vanilla
241 // ExceptionBarrier to report any exceptions that do make their way to us
242 // though.
243 ExceptionBarrier barrier;
244
[email protected]f7817822009-09-24 05:11:58245 HMODULE ieframe_module = LoadLibrary(kIEFrameDll);
246 if (ieframe_module) {
247 typedef HRESULT (__stdcall *IERefreshPolicy)();
248 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>(
249 GetProcAddress(ieframe_module, kIERefreshPolicy));
250
251 if (ie_refresh_policy) {
252 hr = ie_refresh_policy();
253 } else {
254 hr = HRESULT_FROM_WIN32(GetLastError());
255 }
[email protected]357219de2009-10-06 23:40:22256
[email protected]f7817822009-09-24 05:11:58257 FreeLibrary(ieframe_module);
258 } else {
259 hr = HRESULT_FROM_WIN32(GetLastError());
260 }
261
262 return hr;
263}
264
265HRESULT RegisterChromeTabBHO() {
266 RegKey ie_bho_key;
267 if (!ie_bho_key.Create(HKEY_LOCAL_MACHINE, kBhoRegistryPath,
268 KEY_CREATE_SUB_KEY)) {
269 DLOG(WARNING) << "Failed to open registry key "
270 << kBhoRegistryPath
271 << " for write";
272 return E_FAIL;
273 }
274
275 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
276 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
277 arraysize(bho_class_id_as_string));
278
279 if (!ie_bho_key.CreateKey(bho_class_id_as_string, KEY_READ | KEY_WRITE)) {
280 DLOG(WARNING) << "Failed to create bho registry key under "
281 << kBhoRegistryPath
282 << " for write";
283 return E_FAIL;
284 }
285
286 ie_bho_key.WriteValue(kBhoNoLoadExplorerValue, 1);
287 DLOG(INFO) << "Registered ChromeTab BHO";
288
[email protected]3f55e872009-10-17 04:48:37289 // We now add the chromeframe user agent at runtime.
[email protected]f7817822009-09-24 05:11:58290 RefreshElevationPolicy();
291 return S_OK;
292}
293
294HRESULT UnregisterChromeTabBHO() {
[email protected]3f55e872009-10-17 04:48:37295 // TODO(tommi): remove this in future versions.
[email protected]f7817822009-09-24 05:11:58296 SetClockUserAgent(NULL);
297
298 RegKey ie_bho_key;
299 if (!ie_bho_key.Open(HKEY_LOCAL_MACHINE, kBhoRegistryPath,
300 KEY_READ | KEY_WRITE)) {
301 DLOG(WARNING) << "Failed to open registry key "
302 << kBhoRegistryPath
303 << " for write.";
304 return E_FAIL;
305 }
306
307 wchar_t bho_class_id_as_string[MAX_PATH] = {0};
308 StringFromGUID2(CLSID_ChromeFrameBHO, bho_class_id_as_string,
309 arraysize(bho_class_id_as_string));
310
311 if (!ie_bho_key.DeleteKey(bho_class_id_as_string)) {
312 DLOG(WARNING) << "Failed to delete bho registry key "
313 << bho_class_id_as_string
314 << " under "
315 << kBhoRegistryPath;
316 return E_FAIL;
317 }
318
319 DLOG(INFO) << "Unregistered ChromeTab BHO";
320 return S_OK;
321}
322
[email protected]552fb6012010-02-03 17:24:29323HRESULT CleanupCFProtocol() {
324 RegKey protocol_handlers_key;
325 if (protocol_handlers_key.Open(HKEY_LOCAL_MACHINE, kProtocolHandlers,
326 KEY_READ | KEY_WRITE)) {
327 RegKey cf_protocol_key;
328 if (cf_protocol_key.Open(protocol_handlers_key.Handle(), L"cf",
329 KEY_QUERY_VALUE)) {
330 std::wstring protocol_clsid_string;
331 if (cf_protocol_key.ReadValue(L"CLSID", &protocol_clsid_string)) {
332 CLSID protocol_clsid = {0};
333 IIDFromString(protocol_clsid_string.c_str(), &protocol_clsid);
334 if (IsEqualGUID(protocol_clsid, CLSID_ChromeProtocol))
335 protocol_handlers_key.DeleteKey(L"cf");
336 }
337 }
338 }
339
340 return S_OK;
341}
342
[email protected]f7817822009-09-24 05:11:58343// Used to determine whether the DLL can be unloaded by OLE
344STDAPI DllCanUnloadNow() {
345 return _AtlModule.DllCanUnloadNow();
346}
347
348// Returns a class factory to create an object of the requested type
349STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
[email protected]52749842010-05-07 21:34:41350 // If we found another module present when we were loaded, then delegate to
351 // that:
352 if (g_dll_get_class_object_redir_ptr) {
353 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
[email protected]8adbf7e52010-04-14 20:03:23354 } else {
[email protected]0794db62010-05-05 21:30:07355 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
[email protected]8adbf7e52010-04-14 20:03:23356 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
357 }
[email protected]f7817822009-09-24 05:11:58358}
359
360// DllRegisterServer - Adds entries to the system registry
361STDAPI DllRegisterServer() {
362 // registers object, typelib and all interfaces in typelib
363 HRESULT hr = _AtlModule.DllRegisterServer(TRUE);
364
[email protected]f7817822009-09-24 05:11:58365 if (SUCCEEDED(hr)) {
366 // Best effort attempt to register the BHO. At this point we silently
367 // ignore any errors during registration. There are some traces emitted
368 // to the debug log.
369 RegisterChromeTabBHO();
[email protected]357219de2009-10-06 23:40:22370 if (!RegisterSecuredMimeHandler(true))
371 hr = E_FAIL;
[email protected]f7817822009-09-24 05:11:58372 }
373
[email protected]c41468f2009-11-11 20:39:18374 if (UtilIsPersistentNPAPIMarkerSet()) {
375 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, TRUE);
376 }
377
[email protected]f7817822009-09-24 05:11:58378 return hr;
379}
380
381// DllUnregisterServer - Removes entries from the system registry
382STDAPI DllUnregisterServer() {
383 HRESULT hr = _AtlModule.DllUnregisterServer(TRUE);
384
[email protected]f7817822009-09-24 05:11:58385 if (SUCCEEDED(hr)) {
386 // Best effort attempt to unregister the BHO. At this point we silently
387 // ignore any errors during unregistration. There are some traces emitted
388 // to the debug log.
389 UnregisterChromeTabBHO();
[email protected]357219de2009-10-06 23:40:22390 if (!RegisterSecuredMimeHandler(false))
391 hr = E_FAIL;
[email protected]f7817822009-09-24 05:11:58392 }
[email protected]c41468f2009-11-11 20:39:18393
394 if (UtilIsNPAPIPluginRegistered()) {
395 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, FALSE);
396 }
397
[email protected]552fb6012010-02-03 17:24:29398 // TODO(joshia): Remove after 2 refresh releases
399 CleanupCFProtocol();
[email protected]f7817822009-09-24 05:11:58400 return hr;
401}
402
[email protected]c41468f2009-11-11 20:39:18403// Registers the NPAPI plugin and sets the persistent marker that tells us
404// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58405STDAPI RegisterNPAPIPlugin() {
406 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
407 TRUE);
[email protected]c41468f2009-11-11 20:39:18408 if (SUCCEEDED(hr)) {
409 if (!UtilChangePersistentNPAPIMarker(true)) {
410 hr = E_FAIL;
411 }
412 }
[email protected]f7817822009-09-24 05:11:58413 return hr;
414}
415
[email protected]c41468f2009-11-11 20:39:18416// Unregisters the NPAPI plugin and clears the persistent marker that tells us
417// to re-register it through updates.
[email protected]f7817822009-09-24 05:11:58418STDAPI UnregisterNPAPIPlugin() {
419 HRESULT hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI,
420 FALSE);
[email protected]c41468f2009-11-11 20:39:18421 if (SUCCEEDED(hr)) {
422 if (!UtilChangePersistentNPAPIMarker(false)) {
423 hr = E_FAIL;
424 }
425 }
[email protected]f7817822009-09-24 05:11:58426 return hr;
427}
[email protected]357219de2009-10-06 23:40:22428
429class SecurityDescBackup {
430 public:
431 explicit SecurityDescBackup(const std::wstring& backup_key)
432 : backup_key_name_(backup_key) {}
433 ~SecurityDescBackup() {}
434
435 // Save given security descriptor to the backup key.
436 bool SaveSecurity(const CSecurityDesc& sd) {
437 CString str;
438 if (!sd.ToString(&str))
439 return false;
440
441 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(),
442 KEY_READ | KEY_WRITE);
443 if (backup_key.Valid()) {
444 return backup_key.WriteValue(NULL, str.GetString());
445 }
446
447 return false;
448 }
449
450 // Restore security descriptor from backup key to given key name.
451 bool RestoreSecurity(const wchar_t* key_name) {
452 std::wstring sddl;
453 if (!ReadBackupKey(&sddl))
454 return false;
455
456 // Create security descriptor from string.
457 CSecurityDesc sd;
458 if (!sd.FromString(sddl.c_str()))
459 return false;
460
461 bool result = true;
462 // Restore DACL and Owner of the key from saved security descriptor.
463 CDacl dacl;
464 CSid owner;
465 sd.GetDacl(&dacl);
466 sd.GetOwner(&owner);
467
468 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name),
469 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
470 const_cast<SID*>(owner.GetPSID()), NULL,
471 const_cast<ACL*>(dacl.GetPACL()), NULL);
472
473 DeleteBackupKey();
474 return (error == ERROR_SUCCESS);
475 }
476
477 private:
478 // Read SDDL string from backup key
479 bool ReadBackupKey(std::wstring* sddl) {
480 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ);
481 if (!backup_key.Valid())
482 return false;
483
484 DWORD len = 0;
485 DWORD reg_type = REG_NONE;
486 if (!backup_key.ReadValue(NULL, NULL, &len, &reg_type))
487 return false;
488
489 if (reg_type != REG_SZ)
490 return false;
491
492 size_t wchar_count = 1 + len / sizeof(wchar_t);
493 if (!backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len,
494 &reg_type)) {
495 return false;
496 }
497
498 return true;
499 }
500
501 void DeleteBackupKey() {
502 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str());
503 }
504
505 std::wstring backup_key_name_;
506};
507
508struct TokenWithPrivileges {
509 TokenWithPrivileges() {
510 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
511 token_.GetUser(&user_);
512 }
513
514 ~TokenWithPrivileges() {
515 token_.EnableDisablePrivileges(take_ownership_);
516 token_.EnableDisablePrivileges(restore_);
517 }
518
519 bool EnablePrivileges() {
520 if (take_ownership_.GetCount() == 0)
521 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege",
522 &take_ownership_))
523 return false;
524
525 if (restore_.GetCount() == 0)
526 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_))
527 return false;
528
529 return true;
530 }
531
532 const CSid& GetUser() const {
533 return user_;
534 }
535
536 private:
537 CAccessToken token_;
538 CTokenPrivileges take_ownership_;
539 CTokenPrivileges restore_;
540 CSid user_;
541};
542
543static bool SetOrDeleteMimeHandlerKey(bool set) {
544 std::wstring key_name = kInternetSettings;
545 key_name.append(L"\\Secure Mime Handlers");
546 RegKey key(HKEY_LOCAL_MACHINE, key_name.c_str(), KEY_READ | KEY_WRITE);
547 if (!key.Valid())
548 return false;
549
550 bool result;
551 if (set) {
552 result = key.WriteValue(L"ChromeTab.ChromeActiveDocument", 1);
553 result = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1) && result;
554 } else {
555 result = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
556 result = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1") && result;
557 }
558
559 return result;
560}
561
562bool RegisterSecuredMimeHandler(bool enable) {
563 if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA) {
564 return SetOrDeleteMimeHandlerKey(enable);
565 }
566
567 std::wstring mime_key = kInternetSettings;
568 mime_key.append(L"\\Secure Mime Handlers");
569 std::wstring backup_key = kInternetSettings;
570 backup_key.append(L"\\__backup_SMH__");
571 std::wstring object_name = L"MACHINE\\";
572 object_name.append(mime_key);
573
574 TokenWithPrivileges token_;
575 if (!token_.EnablePrivileges())
576 return false;
577
578 // If there is a backup key - something bad happened; try to restore
579 // security on "Secure Mime Handlers" from the backup.
580 SecurityDescBackup backup(backup_key);
581 backup.RestoreSecurity(object_name.c_str());
582
583 // Read old security descriptor of the Mime key first.
584 CSecurityDesc sd;
585 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) {
586 return false;
587 }
588
589 backup.SaveSecurity(sd);
590 bool result = false;
591 // set new owner
592 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) {
593 // set new dacl
594 CDacl new_dacl;
595 sd.GetDacl(&new_dacl);
596 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ);
597 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) {
598 result = SetOrDeleteMimeHandlerKey(enable);
599 }
600 }
601
602 backup.RestoreSecurity(object_name.c_str());
603 return result;
604}