1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_module.h"
6 
7 #include <process.h>
8 
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/strings/string_util.h"
14 #include "base/win/win_util.h"
15 #include "base/win/windows_version.h"
16 #include "chrome/common/chrome_version.h"
17 #include "chrome/credential_provider/eventlog/gcp_eventlog_messages.h"
18 #include "chrome/credential_provider/extension/extension_utils.h"
19 #include "chrome/credential_provider/extension/os_service_manager.h"
20 #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
21 #include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
22 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_filter.h"
23 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
24 #include "chrome/credential_provider/gaiacp/gcp_crash_reporting.h"
25 #include "chrome/credential_provider/gaiacp/grit/gaia_static_resources.h"
26 #include "chrome/credential_provider/gaiacp/logging.h"
27 #include "chrome/credential_provider/gaiacp/mdm_utils.h"
28 #include "chrome/credential_provider/gaiacp/reg_utils.h"
29 #include "components/crash/core/app/crash_switches.h"
30 #include "content/public/common/content_switches.h"
31 
32 namespace credential_provider {
33 
34 namespace {
35 
InvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)36 void InvalidParameterHandler(const wchar_t* expression,
37                              const wchar_t* function,
38                              const wchar_t* file,
39                              unsigned int line,
40                              uintptr_t pReserved) {
41   LOGFN(ERROR) << "func=" << (function ? function : L"-")
42                << " expression=" << (expression ? expression : L"-")
43                << " file=" << (file ? file : L"-") << " line=" << line;
44 }
45 
CheckGCPWExtensionStatus(void * param)46 unsigned __stdcall CheckGCPWExtensionStatus(void* param) {
47   LOGFN(VERBOSE);
48   if (!credential_provider::extension::IsGCPWExtensionRunning()) {
49     credential_provider::extension::OSServiceManager* service_manager =
50         credential_provider::extension::OSServiceManager::Get();
51 
52     DWORD error_code = service_manager->StartGCPWService();
53     if (error_code != ERROR_SUCCESS) {
54       LOGFN(WARNING) << "Unable to start GCPW extension win32=" << error_code;
55     }
56   }
57   return 0;
58 }
59 
60 }  // namespace
61 
CGaiaCredentialProviderModule()62 CGaiaCredentialProviderModule::CGaiaCredentialProviderModule()
63     : ATL::CAtlDllModuleT<CGaiaCredentialProviderModule>(),
64       exit_manager_(nullptr),
65       gcpw_extension_check_performed_(0),
66       crashpad_initialized_(0) {}
67 
~CGaiaCredentialProviderModule()68 CGaiaCredentialProviderModule::~CGaiaCredentialProviderModule() {}
69 
70 // static
71 HRESULT WINAPI
UpdateRegistryAppId(BOOL do_register)72 CGaiaCredentialProviderModule::UpdateRegistryAppId(BOOL do_register) throw() {
73   base::FilePath eventlog_path;
74   HRESULT hr = CGaiaCredentialBase::GetInstallDirectory(&eventlog_path);
75   if (FAILED(hr)) {
76     LOGFN(ERROR) << "CGaiaCredentialBase::GetInstallDirectory hr=" << putHR(hr);
77     return hr;
78   }
79   eventlog_path =
80       eventlog_path.Append(FILE_PATH_LITERAL("gcp_eventlog_provider.dll"));
81 
82   auto provider_guid_string =
83       base::win::WStringFromGUID(CLSID_GaiaCredentialProvider);
84 
85   auto filter_guid_string =
86       base::win::WStringFromGUID(CLSID_CGaiaCredentialProviderFilter);
87 
88   ATL::_ATL_REGMAP_ENTRY regmap[] = {
89       {L"CP_CLASS_GUID", base::as_wcstr(provider_guid_string.c_str())},
90       {L"CP_FILTER_CLASS_GUID", base::as_wcstr(filter_guid_string.c_str())},
91       {L"VERSION", TEXT(CHROME_VERSION_STRING)},
92       {L"EVENTLOG_PATH", eventlog_path.value().c_str()},
93       {nullptr, nullptr},
94   };
95 
96   return ATL::_pAtlModule->UpdateRegistryFromResource(
97       IDR_GAIACREDENTIALPROVIDER, do_register, regmap);
98 }
99 
RefreshTokenHandleValidity()100 void CGaiaCredentialProviderModule::RefreshTokenHandleValidity() {
101   if (!token_handle_validity_refreshed_) {
102     credential_provider::AssociatedUserValidator::Get()
103         ->StartRefreshingTokenHandleValidity();
104     token_handle_validity_refreshed_ = true;
105   }
106 }
107 
CheckGCPWExtension()108 void CGaiaCredentialProviderModule::CheckGCPWExtension() {
109   LOGFN(VERBOSE);
110   if (extension::IsGCPWExtensionEnabled() &&
111       ::InterlockedCompareExchange(&gcpw_extension_check_performed_, 1, 0) ==
112           0) {
113     gcpw_extension_checker_thread_handle_ =
114         reinterpret_cast<HANDLE>(_beginthreadex(
115             nullptr, 0, CheckGCPWExtensionStatus, nullptr, 0, nullptr));
116   }
117 }
118 
InitializeCrashReporting()119 void CGaiaCredentialProviderModule::InitializeCrashReporting() {
120   // Perform a thread unsafe check to see whether crash reporting is
121   // initialized. Thread safe check is performed right before initializing crash
122   // reporting.
123   if (GetGlobalFlagOrDefault(kRegInitializeCrashReporting, 1) &&
124       !crashpad_initialized_) {
125     base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
126 
127     if (!base::EndsWith(cmd_line->GetProgram().value(), L"gcp_unittests.exe",
128                         base::CompareCase::INSENSITIVE_ASCII) &&
129         cmd_line->GetSwitchValueASCII(switches::kProcessType) !=
130             crash_reporter::switches::kCrashpadHandler &&
131         ::InterlockedCompareExchange(&crashpad_initialized_, 1, 0) == 0) {
132       ConfigureGcpCrashReporting(*cmd_line);
133       LOGFN(VERBOSE) << "Crash reporting was initialized.";
134     }
135   }
136 }
137 
LogProcessDetails()138 void CGaiaCredentialProviderModule::LogProcessDetails() {
139   wchar_t process_name[MAX_PATH] = {0};
140   GetModuleFileName(nullptr, process_name, MAX_PATH);
141 
142   LOGFN(INFO) << "GCPW Initialized in " << process_name
143               << " GCPW Version: " << (CHROME_VERSION_STRING)
144               << " Windows Build: "
145               << base::win::OSInfo::GetInstance()->Kernel32BaseVersion()
146               << " Version:" << GetWindowsVersion();
147 }
148 
DllMain(HINSTANCE,DWORD reason,LPVOID reserved)149 BOOL CGaiaCredentialProviderModule::DllMain(HINSTANCE /*hinstance*/,
150                                             DWORD reason,
151                                             LPVOID reserved) {
152   switch (reason) {
153     case DLL_PROCESS_ATTACH: {
154       exit_manager_ = std::make_unique<base::AtExitManager>();
155 
156       _set_invalid_parameter_handler(InvalidParameterHandler);
157 
158       // Initialize base.  Command line will be set from GetCommandLineW().
159       base::CommandLine::Init(0, nullptr);
160 
161       // Initialize logging.
162       logging::LoggingSettings settings;
163       settings.logging_dest = logging::LOG_NONE;
164       logging::InitLogging(settings);
165       logging::SetLogItems(true,    // Enable process id.
166                            true,    // Enable thread id.
167                            true,    // Enable timestamp.
168                            false);  // Enable tickcount.
169       logging::SetEventSource("GCPW", GCPW_CATEGORY, MSG_LOG_MESSAGE);
170       if (GetGlobalFlagOrDefault(kRegEnableVerboseLogging, 0))
171         logging::SetMinLogLevel(logging::LOG_VERBOSE);
172       break;
173     }
174     case DLL_PROCESS_DETACH:
175       LOGFN(VERBOSE) << "DllMain(DLL_PROCESS_DETACH)";
176 
177       // When this DLL is loaded for testing, don't reset the command line
178       // since it causes tests to crash.
179       if (!is_testing_)
180         base::CommandLine::Reset();
181 
182       _set_invalid_parameter_handler(nullptr);
183       exit_manager_.reset();
184       break;
185 
186     default:
187       break;
188   }
189 
190   return ATL::CAtlDllModuleT<CGaiaCredentialProviderModule>::DllMain(reason,
191                                                                      reserved);
192 }
193 
194 }  // namespace credential_provider
195