blob: 78dcbcefb3eaa27a7bf810974ca91212911ff6e6 [file] [log] [blame]
// Copyright 2007-2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
#include "omaha/worker/application_usage_data.h"
#include "omaha/common/logging.h"
#include "omaha/common/reg_key.h"
#include "omaha/common/user_info.h"
#include "omaha/common/utils.h"
#include "omaha/common/vistautil.h"
#include "omaha/goopdate/const_goopdate.h"
#include "omaha/goopdate/goopdate_utils.h"
namespace omaha {
ApplicationUsageData::ApplicationUsageData(bool is_machine,
bool check_low_integrity)
: exists_(false),
did_run_(false),
is_machine_(is_machine),
is_pre_update_check_(true),
check_low_integrity_(check_low_integrity) {
}
ApplicationUsageData::~ApplicationUsageData() {
}
HRESULT ApplicationUsageData::ReadDidRun(const CString& app_guid) {
CORE_LOG(L4, (_T("[ApplicationUsageData::ReadDidRun][%s]"), app_guid));
is_pre_update_check_ = true;
return ProcessDidRun(app_guid);
}
HRESULT ApplicationUsageData::ResetDidRun(const CString& app_guid) {
CORE_LOG(L4, (_T("[ApplicationUsageData::ResetDidRun][%s]"), app_guid));
is_pre_update_check_ = false;
return ProcessDidRun(app_guid);
}
HRESULT ApplicationUsageData::ProcessDidRun(const CString& app_guid) {
CORE_LOG(L4, (_T("[ApplicationUsageData::ProcessDidRun][%s]"), app_guid));
return is_machine_ ? ProcessMachineDidRun(app_guid) :
ProcessUserDidRun(app_guid);
}
HRESULT ApplicationUsageData::ProcessMachineDidRun(const CString& app_guid) {
ASSERT1(is_machine_);
// Logic is as follows:
// for each user under HKU\<sid>
// pre/post process HKU\<sid>
// if vista
// pre/post process HKU\<lowintegrity IE>\<sid>
// pre/post process HKLM
RegKey users_key;
HRESULT hr = users_key.Open(USERS_KEY, KEY_READ);
if (SUCCEEDED(hr)) {
uint32 num_users = users_key.GetSubkeyCount();
for (uint32 i = 0; i < num_users; ++i) {
CString sub_key_name;
hr = users_key.GetSubkeyNameAt(i, &sub_key_name);
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[Key enum failed.][0x%08x][%d][%s]"),
hr, i, USERS_KEY));
continue;
}
CString temp_key = AppendRegKeyPath(USERS_KEY,
sub_key_name,
GOOPDATE_REG_RELATIVE_CLIENT_STATE);
CString user_state_key_name = AppendRegKeyPath(temp_key, app_guid);
hr = ProcessKey(user_state_key_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));
}
if (check_low_integrity_) {
// If we are running on vista we need to also look at the low
// integrity IE key where IE can write to. Note that we cannot
// use the IEGetWriteableHKCU function since this function assumes
// that we are running with the user's credentials.
CString temp_key = AppendRegKeyPath(USERS_KEY,
sub_key_name,
USER_REG_VISTA_LOW_INTEGRITY_HKCU);
CString li_hkcu_name = AppendRegKeyPath(
AppendRegKeyPath(
temp_key,
sub_key_name,
GOOPDATE_REG_RELATIVE_CLIENT_STATE),
app_guid);
hr = ProcessKey(li_hkcu_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));
}
}
} // End of for
// Now Process the machine did run value also.
CString machine_state_key_name =
goopdate_utils::GetAppClientStateKey(true, app_guid);
hr = ProcessBackWardCompatKey(machine_state_key_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[ProcessBackWardCompatKey failed][0x%08x][%s]"),
hr, machine_state_key_name));
}
} else {
CORE_LOG(LW, (_T("[Key open failed.][0x%08x][%s]"), hr, USERS_KEY));
}
return S_OK;
}
HRESULT ApplicationUsageData::ProcessUserDidRun(const CString& app_guid) {
ASSERT1(!is_machine_);
// Logic:
// Pre/Post process HKCU\
// if vista:
// Pre/Post process HKCU\LowIntegrity
CString state_key_name = goopdate_utils::GetAppClientStateKey(false,
app_guid);
HRESULT hr = ProcessKey(state_key_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[ProcessKey failed][0x%08x][%s]"),
hr, state_key_name));
}
if (check_low_integrity_) {
// If we are running on vista we need to also look at the low
// integrity IE key where IE can write to. To avoid loading
// ieframe.dll into our process, we just use the registry
// key location directly instead of using IEGetWriteableHKCU
CString sid;
hr = user_info::GetCurrentUser(NULL, NULL, &sid);
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[GetCurrentUser failed][0x%08x][%s]"),
hr, app_guid));
return hr;
}
CString temp_name = AppendRegKeyPath(USER_KEY_NAME,
USER_REG_VISTA_LOW_INTEGRITY_HKCU,
sid);
CString lowintegrity_hkcu_name = AppendRegKeyPath(
temp_name,
GOOPDATE_REG_RELATIVE_CLIENT_STATE,
app_guid);
hr = ProcessKey(lowintegrity_hkcu_name);
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[Could not ProcessKey][0x%08x][%s]"),
hr, app_guid));
}
}
return S_OK;
}
HRESULT ApplicationUsageData::ProcessKey(const CString& key_name) {
return is_pre_update_check_ ? ProcessPreUpdateCheck(key_name) :
ProcessPostUpdateCheck(key_name);
}
HRESULT ApplicationUsageData::ProcessPreUpdateCheck(const CString& key_name) {
// Read in the regkey value if it exists, and or it with the previous value.
RegKey key;
HRESULT hr = key.Open(key_name, KEY_READ);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
return hr;
}
// Now that we have the key, we should try and read the value of the
// did run key.
CString did_run_str(_T("0"));
hr = key.GetValue(kRegValueDidRun, &did_run_str);
if (FAILED(hr)) {
CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),
hr, key_name, kRegValueDidRun));
return hr;
}
if (did_run_str == _T("1")) {
did_run_ |= true;
}
exists_ |= true;
return hr;
}
HRESULT ApplicationUsageData::ProcessBackWardCompatKey(
const CString& key_name) {
// This method exists to support the installers that have not been
// updated to write to the HKCU key. Remove when we have all the installers
// correcly updated.
if (is_pre_update_check_) {
// Read in the regkey value if it exists, and or it with the previous value.
RegKey key;
HRESULT hr = key.Open(key_name, KEY_READ);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
return hr;
}
// Now that we have the key, we should try and read the value of the
// did run key.
CString did_run_str(_T("0"));
hr = key.GetValue(kRegValueDidRun, &did_run_str);
if (FAILED(hr)) {
CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),
hr, key_name, kRegValueDidRun));
return hr;
}
if (did_run_str == _T("1")) {
did_run_ |= true;
}
exists_ |= true;
return hr;
} else {
RegKey key;
HRESULT hr = key.Open(key_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
return hr;
}
// If the value exists, then it means that the installer has been updated,
// and we delete the machine value.
if (exists_) {
hr = RegKey::DeleteValue(key_name, kRegValueDidRun);
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[RegKey::DeleteValue failed][0x%08x][%s]"),
hr, key_name));
return hr;
}
} else {
// Since the value does not exist else where, we reset the value in the
// HKLM key to zero.
exists_ |= true;
CString did_run_str(_T("0"));
if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {
hr = key.SetValue(kRegValueDidRun, _T("0"));
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),
hr, key_name));
return hr;
}
}
}
}
return S_OK;
}
HRESULT ApplicationUsageData::ProcessPostUpdateCheck(const CString& key_name) {
RegKey key;
HRESULT hr = key.Open(key_name);
if (FAILED(hr)) {
CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
return hr;
}
CString did_run_str(_T("0"));
if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {
exists_ |= true;
hr = key.SetValue(kRegValueDidRun, _T("0"));
if (FAILED(hr)) {
CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),
hr, key_name));
return hr;
}
}
return S_OK;
}
} // namespace omaha