Skip to content

Commit

Permalink
Implement the Omaha Cloud Policies Fetcher.
Browse files Browse the repository at this point in the history
  • Loading branch information
sorinj committed Jun 5, 2019
1 parent 5540cad commit ed71525
Show file tree
Hide file tree
Showing 14 changed files with 839 additions and 188 deletions.
12 changes: 9 additions & 3 deletions omaha/base/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,19 +178,25 @@ const TCHAR* const kChromeAppId = CHROME_APP_ID;
//
// Directory names
//
#define OFFLINE_DIR_NAME _T("Offline")
#define OFFLINE_DIR_NAME _T("Offline")
#define DOWNLOAD_DIR_NAME _T("Download")
#define INSTALL_WORKING_DIR_NAME _T("Install")

// Directories relative to \Google
#define OMAHA_REL_COMPANY_DIR SHORT_COMPANY_NAME
#define OMAHA_REL_CRASH_DIR OMAHA_REL_COMPANY_DIR _T("\\CrashReports")
#define OMAHA_REL_POLICY_RESPONSES_DIR OMAHA_REL_COMPANY_DIR _T("\\Policies")

// Directories relative to \Google\Update
#define OMAHA_REL_GOOPDATE_INSTALL_DIR \
OMAHA_REL_COMPANY_DIR _T("\\") PRODUCT_NAME
#define OMAHA_REL_LOG_DIR OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Log")
#define OMAHA_REL_OFFLINE_STORAGE_DIR \
OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\") OFFLINE_DIR_NAME
#define OMAHA_REL_DOWNLOAD_STORAGE_DIR \
OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Download")
OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\") DOWNLOAD_DIR_NAME
#define OMAHA_REL_INSTALL_WORKING_DIR \
OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Install")
OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\") INSTALL_WORKING_DIR_NAME

// This directory is relative to the user profile app data local.
#define LOCAL_APPDATA_REL_TEMP_DIR _T("\\Temp")
Expand Down
9 changes: 9 additions & 0 deletions omaha/common/config_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,15 @@ HRESULT ConfigManager::GetDeviceManagementUrl(CString* url) const {
return S_OK;
}

CPath ConfigManager::GetPolicyResponsesDir() const {
CString path;
VERIFY1(SUCCEEDED(GetDir32(CSIDL_PROGRAM_FILES,
CString(OMAHA_REL_POLICY_RESPONSES_DIR),
true,
&path)));
return CPath(path);
}

#endif // defined(HAS_DEVICE_MANAGEMENT)

// Returns the override from the registry locations if present. Otherwise,
Expand Down
5 changes: 5 additions & 0 deletions omaha/common/config_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define OMAHA_COMMON_CONFIG_MANAGER_H_

#include <windows.h>
#include <atlpath.h>
#include <atlstr.h>
#include "base/basictypes.h"
#include "omaha/base/constants.h"
Expand Down Expand Up @@ -175,6 +176,10 @@ class ConfigManager {
#if defined(HAS_DEVICE_MANAGEMENT)
// Returns the Device Management API url.
HRESULT GetDeviceManagementUrl(CString* url) const;

// Returns the directory under which the Device Management policies are
// persisted.
CPath GetPolicyResponsesDir() const;
#endif

// Returns the time interval between update checks in seconds.
Expand Down
1 change: 1 addition & 0 deletions omaha/common/const_goopdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ const int kNetworkRequestEventId = 20;
// Device management events.
const int kEnrollmentFailedEventId = 30;
const int kEnrollmentRequiresNetworkEventId = 31;
const int kRefreshPoliciesFailedEventId = 32;

// Maximum value the server can respond for elapsed_seconds attribute in
// <daystart ...> element. The value is one day plus an hour ("fall back"
Expand Down
204 changes: 161 additions & 43 deletions omaha/goopdate/dm_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

#include "omaha/goopdate/dm_client.h"

#include <shlobj.h>
#include <memory>
#include <utility>

#include "omaha/base/app_util.h"
#include "omaha/base/constants.h"
Expand Down Expand Up @@ -55,6 +57,13 @@ HRESULT RegisterIfNeeded(DmStorage* dm_storage) {
ASSERT1(dm_storage);
OPT_LOG(L1, (_T("[DmClient::RegisterIfNeeded]")));

// No work to be done if the process is not running as an administrator, since
// we will not be able to persist anything.
if (!::IsUserAnAdmin()) {
OPT_LOG(L1, (_T("[RegisterIfNeeded][Process not Admin, exiting early]")));
return S_FALSE;
}

// No work to be done if a DM token was found.
CStringA dm_token = dm_storage->GetDmToken();
if (!dm_token.IsEmpty()) {
Expand All @@ -76,8 +85,10 @@ HRESULT RegisterIfNeeded(DmStorage* dm_storage) {
return E_FAIL;
}

// RegisterWithRequest owns the SimpleRequest being created here.
HRESULT hr = internal::RegisterWithRequest(new SimpleRequest,
enrollment_token, device_id,
enrollment_token,
device_id,
&dm_token);
if (FAILED(hr)) {
return hr;
Expand All @@ -94,6 +105,53 @@ HRESULT RegisterIfNeeded(DmStorage* dm_storage) {
return S_OK;
}

HRESULT RefreshPolicies() {
// No work to be done if the process is not running as an administrator, since
// we will not be able to persist anything.
if (!::IsUserAnAdmin()) {
OPT_LOG(L1, (_T("[RefreshPolicies][Process not Admin, exiting early]")));
return S_FALSE;
}

DmStorage* const dm_storage = DmStorage::Instance();
const CString dm_token = CString(dm_storage->GetDmToken());
if (dm_token.IsEmpty()) {
OPT_LOG(L1, (_T("[Skipping RefreshPolicies as there is no DMToken]")));
return S_FALSE;
}

const CString device_id = dm_storage->GetDeviceId();
if (device_id.IsEmpty()) {
REPORT_LOG(LE, (_T("[Device ID not found]")));
return E_FAIL;
}

PolicyResponsesMap responses;

// FetchPolicies owns the SimpleRequest being created here.
HRESULT hr = internal::FetchPolicies(new SimpleRequest,
dm_token,
device_id,
&responses);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[FetchPolicies failed][%#x]"), hr));
return hr;
}

const CPath policy_responses_dir(
ConfigManager::Instance()->GetPolicyResponsesDir());

hr = DmStorage::PersistPolicies(policy_responses_dir, responses);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[PersistPolicies failed][%#x]"), hr));
return hr;
}

OPT_LOG(L1, (_T("[RefreshPolicies complete]")));

return S_OK;
}

namespace internal {

HRESULT RegisterWithRequest(HttpRequestInterface* http_request,
Expand All @@ -102,6 +160,94 @@ HRESULT RegisterWithRequest(HttpRequestInterface* http_request,
CStringA* dm_token) {
ASSERT1(http_request);
ASSERT1(dm_token);

std::vector<std::pair<CString, CString>> query_params = {
{_T("request"), _T("register_policy_agent")},
};

// Make the request payload.
CStringA payload = SerializeRegisterBrowserRequest(
WideToUtf8(app_util::GetHostName()),
CStringA("Windows"),
internal::GetOsVersion());
if (payload.IsEmpty()) {
REPORT_LOG(LE, (_T("[SerializeRegisterBrowserRequest failed]")));
return E_FAIL;
}

std::vector<uint8> response;
HRESULT hr = SendDeviceManagementRequest(
http_request,
payload,
internal::FormatEnrollmentTokenAuthorizationHeader(enrollment_token),
device_id,
std::move(query_params),
&response);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[SendDeviceManagementRequest failed][%#x]"), hr));
return hr;
}

hr = ParseDeviceRegisterResponse(response, dm_token);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[ParseDeviceRegisterResponse failed][%#x]"), hr));
return hr;
}

return S_OK;
}

HRESULT FetchPolicies(HttpRequestInterface* http_request,
const CString& dm_token,
const CString& device_id,
PolicyResponsesMap* responses) {
ASSERT1(http_request);
ASSERT1(!dm_token.IsEmpty());
ASSERT1(responses);

std::vector<std::pair<CString, CString>> query_params = {
{_T("request"), _T("policy")},
};

CStringA payload = SerializePolicyFetchRequest(
CStringA(kGoogleUpdateMachineLevelApps));
if (payload.IsEmpty()) {
REPORT_LOG(LE, (_T("[SerializePolicyFetchRequest failed]")));
return E_FAIL;
}

std::vector<uint8> response;
HRESULT hr = SendDeviceManagementRequest(
http_request,
payload,
FormatDMTokenAuthorizationHeader(dm_token),
device_id,
std::move(query_params),
&response);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[SendDeviceManagementRequest failed][%#x]"), hr));
return hr;
}

hr = ParseDevicePolicyResponse(response, responses);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[ParseDeviceRegisterResponse failed][%#x]"), hr));
return hr;
}

return S_OK;
}

HRESULT SendDeviceManagementRequest(
HttpRequestInterface* http_request,
const CStringA& payload,
const CString& authorization_header,
const CString& device_id,
std::vector<std::pair<CString, CString>> query_params,
std::vector<uint8>* response) {
ASSERT1(http_request);
ASSERT1(response);

// Get the network configuration.
NetworkConfig* network_config = NULL;
NetworkConfigManager& network_config_manager =
Expand All @@ -115,10 +261,7 @@ HRESULT RegisterWithRequest(HttpRequestInterface* http_request,
// Create a network request and configure its headers.
std::unique_ptr<NetworkRequest> request(
new NetworkRequest(network_config->session()));
// DeviceManagementRequestJobImpl::ConfigureRequest.
request->AddHeader(L"Authorization",
internal::FormatEnrollmentTokenAuthorizationHeader(
enrollment_token));
request->AddHeader(_T("Authorization"), authorization_header);

// Set it up
request->AddHttpRequest(http_request);
Expand All @@ -131,42 +274,18 @@ HRESULT RegisterWithRequest(HttpRequestInterface* http_request,
return hr;
}

std::vector<std::pair<CString, CString>> query_params;
// DeviceManagementRequestJob::DeviceManagementRequestJob.
// kParamRequest = kValueRequestTokenEnrollment.
query_params.push_back(std::make_pair(_T("request"),
_T("register_policy_agent")));
// kParamAppType = kValueAppType.
query_params.push_back(std::make_pair(_T("apptype"), _T("Chrome")));
// kParamAgent.
query_params.push_back(std::make_pair(_T("agent"), internal::GetAgent()));
// kParamPlatform.
query_params.push_back(std::make_pair(_T("platform"),
internal::GetPlatform()));

// DeviceManagementRequestJob::SetClientID.
// kParamDeviceID.
query_params.push_back(std::make_pair(_T("deviceid"), device_id));
query_params.emplace_back(_T("agent"), internal::GetAgent());
query_params.emplace_back(_T("apptype"), _T("Chrome"));
query_params.emplace_back(_T("deviceid"), device_id);
query_params.emplace_back(_T("platform"), internal::GetPlatform());

hr = internal::AppendQueryParamsToUrl(query_params, &url);
if (FAILED(hr)) {
REPORT_LOG(LW, (_T("[AppendQueryParamsToUrl failed][%#x]"), hr));
return hr;
}

// Make the request payload.
// DeviceManagementRequest.RegisterBrowserRequest:
CStringA payload = SerializeRegisterBrowserRequest(
WideToUtf8(app_util::GetHostName()), // policy::GetMachineName
CStringA("Windows"), // policy::GetOSPlatform
internal::GetOsVersion()); // policy::GetOSVersion
if (payload.IsEmpty()) {
REPORT_LOG(LE, (_T("[SerializeRegisterBrowserRequest failed]")));
return E_FAIL;
}

std::vector<uint8> response;
hr = request->Post(url, payload, payload.GetLength(), &response);
hr = request->Post(url, payload, payload.GetLength(), response);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[NetworkRequest::Post failed][%#x, %s]"), hr, url));
return hr;
Expand All @@ -177,31 +296,23 @@ HRESULT RegisterWithRequest(HttpRequestInterface* http_request,
REPORT_LOG(LE, (_T("[NetworkRequest::Post failed][status code %d]"),
http_status_code));
CStringA error_message;
hr = ParseDeviceManagementResponseError(response, &error_message);
hr = ParseDeviceManagementResponseError(*response, &error_message);
if (SUCCEEDED(hr)) {
OPT_LOG(LE, (_T("[Server returned: %S]"), error_message));
}
return E_FAIL;
}

hr = ParseDeviceRegisterResponse(response, dm_token);
if (FAILED(hr)) {
REPORT_LOG(LE, (_T("[ParseDeviceRegisterResponse failed][%#x]"), hr));
return hr;
}

return S_OK;
}

CString GetAgent() {
// DeviceManagementServiceConfiguration::GetAgentParameter.
CString agent;
SafeCStringFormat(&agent, _T("%s %s()"), kAppName, GetVersionString());
return agent;
}

CString GetPlatform() {
// DeviceManagementServiceConfiguration::GetPlatformParameter.
const DWORD architecture = SystemInfo::GetProcessorArchitecture();

int major_version = 0;
Expand Down Expand Up @@ -258,6 +369,13 @@ CString FormatEnrollmentTokenAuthorizationHeader(
return header_value;
}

CString FormatDMTokenAuthorizationHeader(
const CString& token) {
CString header_value;
SafeCStringFormat(&header_value, _T("GoogleDMToken token=%s"), token);
return header_value;
}

} // namespace internal
} // namespace dm_client
} // namespace omaha
Loading

0 comments on commit ed71525

Please sign in to comment.