// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_module.h"
#include <process.h>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_version.h"
#include "chrome/credential_provider/eventlog/gcp_eventlog_messages.h"
#include "chrome/credential_provider/extension/extension_utils.h"
#include "chrome/credential_provider/extension/os_service_manager.h"
#include "chrome/credential_provider/gaiacp/associated_user_validator.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_filter.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
#include "chrome/credential_provider/gaiacp/gcp_crash_reporting.h"
#include "chrome/credential_provider/gaiacp/grit/gaia_static_resources.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "components/crash/core/app/crash_switches.h"
#include "components/crash/core/app/crashpad.h"
#include "content/public/common/content_switches.h"
namespace credential_provider {
namespace {
void InvalidParameterHandler(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved) {
LOGFN(ERROR) << "func=" << (function ? function : L"-")
<< " expression=" << (expression ? expression : L"-")
<< " file=" << (file ? file : L"-") << " line=" << line;
}
unsigned __stdcall CheckGCPWExtensionStatus(void* param) {
LOGFN(VERBOSE);
if (!credential_provider::extension::IsGCPWExtensionRunning()) {
credential_provider::extension::OSServiceManager* service_manager =
credential_provider::extension::OSServiceManager::Get();
DWORD error_code = service_manager->StartGCPWService();
if (error_code != ERROR_SUCCESS) {
LOGFN(WARNING) << "Unable to start GCPW extension win32=" << error_code;
}
}
return 0;
}
} // namespace
CGaiaCredentialProviderModule::CGaiaCredentialProviderModule()
: ATL::CAtlDllModuleT<CGaiaCredentialProviderModule>(),
exit_manager_(nullptr),
gcpw_extension_check_performed_(0),
crashpad_initialized_(0) {}
CGaiaCredentialProviderModule::~CGaiaCredentialProviderModule() {}
// static
HRESULT WINAPI
CGaiaCredentialProviderModule::UpdateRegistryAppId(BOOL do_register) throw() {
base::FilePath eventlog_path;
HRESULT hr = CGaiaCredentialBase::GetInstallDirectory(&eventlog_path);
if (FAILED(hr)) {
LOGFN(ERROR) << "CGaiaCredentialBase::GetInstallDirectory hr=" << putHR(hr);
return hr;
}
eventlog_path =
eventlog_path.Append(FILE_PATH_LITERAL("gcp_eventlog_provider.dll"));
auto provider_guid_string =
base::win::WStringFromGUID(CLSID_GaiaCredentialProvider);
auto filter_guid_string =
base::win::WStringFromGUID(CLSID_CGaiaCredentialProviderFilter);
ATL::_ATL_REGMAP_ENTRY regmap[] = {
{L"CP_CLASS_GUID", provider_guid_string.c_str()},
{L"CP_FILTER_CLASS_GUID", filter_guid_string.c_str()},
{L"VERSION", TEXT(CHROME_VERSION_STRING)},
{L"EVENTLOG_PATH", eventlog_path.value().c_str()},
{nullptr, nullptr},
};
return ATL::_pAtlModule->UpdateRegistryFromResource(
IDR_GAIACREDENTIALPROVIDER, do_register, regmap);
}
void CGaiaCredentialProviderModule::RefreshTokenHandleValidity() {
if (!token_handle_validity_refreshed_) {
credential_provider::AssociatedUserValidator::Get()
->StartRefreshingTokenHandleValidity();
token_handle_validity_refreshed_ = true;
}
}
void CGaiaCredentialProviderModule::CheckGCPWExtension() {
LOGFN(VERBOSE);
if (extension::IsGCPWExtensionEnabled() &&
::InterlockedCompareExchange(&gcpw_extension_check_performed_, 1, 0) ==
0) {
gcpw_extension_checker_thread_handle_ =
reinterpret_cast<HANDLE>(_beginthreadex(
nullptr, 0, CheckGCPWExtensionStatus, nullptr, 0, nullptr));
}
}
void CGaiaCredentialProviderModule::InitializeCrashReporting() {
// Perform a thread unsafe check to see whether crash reporting is
// initialized. Thread safe check is performed right before initializing crash
// reporting.
if (GetGlobalFlagOrDefault(kRegInitializeCrashReporting, 1) &&
!crashpad_initialized_) {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!base::EndsWith(cmd_line->GetProgram().value(), L"gcp_unittests.exe",
base::CompareCase::INSENSITIVE_ASCII) &&
cmd_line->GetSwitchValueASCII(switches::kProcessType) !=
crash_reporter::switches::kCrashpadHandler &&
::InterlockedCompareExchange(&crashpad_initialized_, 1, 0) == 0) {
ConfigureGcpCrashReporting(*cmd_line);
LOGFN(VERBOSE) << "Crash reporting was initialized.";
}
}
}
void CGaiaCredentialProviderModule::LogProcessDetails() {
wchar_t process_name[MAX_PATH] = {0};
GetModuleFileName(nullptr, process_name, MAX_PATH);
LOGFN(INFO) << "GCPW Initialized in " << process_name
<< " GCPW Version: " << (CHROME_VERSION_STRING)
<< " Windows Build: " << base::win::OSInfo::Kernel32BaseVersion()
<< " Version:" << GetWindowsVersion();
}
BOOL CGaiaCredentialProviderModule::DllMain(HINSTANCE /*hinstance*/,
DWORD reason,
LPVOID reserved) {
switch (reason) {
case DLL_PROCESS_ATTACH: {
exit_manager_ = std::make_unique<base::AtExitManager>();
_set_invalid_parameter_handler(InvalidParameterHandler);
// Initialize base. Command line will be set from GetCommandLineW().
base::CommandLine::Init(0, nullptr);
// Initialize logging.
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_NONE;
std::wstring log_file_path =
GetGlobalFlagOrDefault(kRegLogFilePath, std::wstring{});
if (not log_file_path.empty()) {
settings.logging_dest = logging::LOG_TO_FILE;
bool append_log = GetGlobalFlagOrDefault(kRegLogFileAppend, 0);
settings.delete_old = append_log ? logging::APPEND_TO_OLD_LOG_FILE
: logging::DELETE_OLD_LOG_FILE;
settings.log_file_path = log_file_path;
}
logging::InitLogging(settings);
logging::SetLogItems(true, // Enable process id.
true, // Enable thread id.
true, // Enable timestamp.
false); // Enable tickcount.
logging::SetEventSource("GCPW", GCPW_CATEGORY, MSG_LOG_MESSAGE);
if (GetGlobalFlagOrDefault(kRegEnableVerboseLogging, 0))
logging::SetMinLogLevel(logging::LOGGING_VERBOSE);
break;
}
case DLL_PROCESS_DETACH:
LOGFN(VERBOSE) << "DllMain(DLL_PROCESS_DETACH)";
// When this DLL is loaded for testing, don't reset the command line
// since it causes tests to crash.
if (!is_testing_)
base::CommandLine::Reset();
_set_invalid_parameter_handler(nullptr);
exit_manager_.reset();
crash_reporter::DestroyCrashpadClient();
break;
default:
break;
}
return ATL::CAtlDllModuleT<CGaiaCredentialProviderModule>::DllMain(reason,
reserved);
}
} // namespace credential_provider