diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-26 00:39:45 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-26 00:39:45 +0000 |
commit | 6dba1dd2efa3ed67bd41312bc682fc12c3c69544 (patch) | |
tree | bfb0bca756ad3e274227d085b82dedda508424fe /rlz/win | |
parent | 4a44f6610eb14a728a22a9dea00d6707d2e616e1 (diff) | |
download | chromium_src-6dba1dd2efa3ed67bd41312bc682fc12c3c69544.zip chromium_src-6dba1dd2efa3ed67bd41312bc682fc12c3c69544.tar.gz chromium_src-6dba1dd2efa3ed67bd41312bc682fc12c3c69544.tar.bz2 |
Revert 144071 - Add a regenerate button to regenerate the password in Windows.
BUG=120480
TEST=Not tested.
Review URL: https://chromiumcodereview.appspot.com/10642009
TBR=zysxqn@google.com
Review URL: https://chromiumcodereview.appspot.com/10659022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144074 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'rlz/win')
-rw-r--r-- | rlz/win/dll/dll_main.cc | 15 | ||||
-rw-r--r-- | rlz/win/dll/exports.cc | 108 | ||||
-rw-r--r-- | rlz/win/lib/lib_mutex.cc | 67 | ||||
-rw-r--r-- | rlz/win/lib/lib_mutex.h | 28 | ||||
-rw-r--r-- | rlz/win/lib/machine_deal.cc | 300 | ||||
-rw-r--r-- | rlz/win/lib/machine_deal.h | 61 | ||||
-rw-r--r-- | rlz/win/lib/machine_deal_test.cc | 156 | ||||
-rw-r--r-- | rlz/win/lib/machine_id_win.cc | 130 | ||||
-rw-r--r-- | rlz/win/lib/process_info.cc | 196 | ||||
-rw-r--r-- | rlz/win/lib/process_info.h | 32 | ||||
-rw-r--r-- | rlz/win/lib/registry_util.cc | 77 | ||||
-rw-r--r-- | rlz/win/lib/registry_util.h | 29 | ||||
-rw-r--r-- | rlz/win/lib/rlz_lib.h | 56 | ||||
-rw-r--r-- | rlz/win/lib/rlz_lib_win.cc | 260 | ||||
-rw-r--r-- | rlz/win/lib/rlz_value_store_registry.cc | 384 | ||||
-rw-r--r-- | rlz/win/lib/rlz_value_store_registry.h | 55 | ||||
-rw-r--r-- | rlz/win/lib/vista_winnt.h | 99 |
17 files changed, 2053 insertions, 0 deletions
diff --git a/rlz/win/dll/dll_main.cc b/rlz/win/dll/dll_main.cc new file mode 100644 index 0000000..943f517 --- /dev/null +++ b/rlz/win/dll/dll_main.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Main function for the RLZ DLL. + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include <windows.h> + +BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved) { + return TRUE; +} + diff --git a/rlz/win/dll/exports.cc b/rlz/win/dll/exports.cc new file mode 100644 index 0000000..efe5cd98 --- /dev/null +++ b/rlz/win/dll/exports.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Functions exported by the RLZ DLL. + +#include "rlz/win/lib/rlz_lib.h" + +#define RLZ_DLL_EXPORT extern "C" __declspec(dllexport) + +RLZ_DLL_EXPORT bool RecordProductEvent(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id) { + return rlz_lib::RecordProductEvent(product, point, event_id); +} + +RLZ_DLL_EXPORT bool GetProductEventsAsCgi(rlz_lib::Product product, + char* unescaped_cgi, + size_t unescaped_cgi_size) { + return rlz_lib::GetProductEventsAsCgi(product, unescaped_cgi, + unescaped_cgi_size); +} +RLZ_DLL_EXPORT bool ClearAllProductEvents(rlz_lib::Product product) { + return rlz_lib::ClearAllProductEvents(product); +} + +RLZ_DLL_EXPORT bool ClearProductEvent(rlz_lib::Product product, + rlz_lib::AccessPoint point, + rlz_lib::Event event_id) { + return rlz_lib::ClearProductEvent(product, point, event_id); +} + +RLZ_DLL_EXPORT bool GetAccessPointRlz(rlz_lib::AccessPoint point, + char* rlz, + size_t rlz_size) { + return rlz_lib::GetAccessPointRlz(point, rlz, rlz_size); +} + +RLZ_DLL_EXPORT bool SetAccessPointRlz(rlz_lib::AccessPoint point, + const char* new_rlz) { + return rlz_lib::SetAccessPointRlz(point, new_rlz); +} + +RLZ_DLL_EXPORT bool CreateMachineState() { + return rlz_lib::CreateMachineState(); +} + +RLZ_DLL_EXPORT bool SetMachineDealCode(const char* dcc) { + return rlz_lib::SetMachineDealCode(dcc); +} + +RLZ_DLL_EXPORT bool GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size) { + return rlz_lib::GetMachineDealCodeAsCgi(cgi, cgi_size); +} + +RLZ_DLL_EXPORT bool GetMachineDealCode2(char* dcc, size_t dcc_size) { + return rlz_lib::GetMachineDealCode(dcc, dcc_size); +} + +RLZ_DLL_EXPORT bool GetPingParams(rlz_lib::Product product, + const rlz_lib::AccessPoint* access_points, + char* unescaped_cgi, + size_t unescaped_cgi_size) { + return rlz_lib::GetPingParams(product, access_points, unescaped_cgi, + unescaped_cgi_size); +} + +RLZ_DLL_EXPORT bool ParsePingResponse(rlz_lib::Product product, + const char* response) { + return rlz_lib::ParsePingResponse(product, response); +} + +RLZ_DLL_EXPORT bool IsPingResponseValid(const char* response, + int* checksum_idx) { + return rlz_lib::IsPingResponseValid(response, checksum_idx); +} + +RLZ_DLL_EXPORT bool SetMachineDealCodeFromPingResponse(const char* response) { + return rlz_lib::SetMachineDealCodeFromPingResponse(response); +} + +RLZ_DLL_EXPORT bool SendFinancialPing(rlz_lib::Product product, + const rlz_lib::AccessPoint* access_points, + const char* product_signature, + const char* product_brand, + const char* product_id, + const char* product_lang, + bool exclude_machine_id) { + return rlz_lib::SendFinancialPing(product, access_points, product_signature, + product_brand, product_id, product_lang, exclude_machine_id); +} + +RLZ_DLL_EXPORT bool SendFinancialPingNoDelay( + rlz_lib::Product product, + const rlz_lib::AccessPoint* access_points, + const char* product_signature, + const char* product_brand, + const char* product_id, + const char* product_lang, + bool exclude_machine_id) { + return rlz_lib::SendFinancialPing(product, access_points, product_signature, + product_brand, product_id, product_lang, exclude_machine_id, true); +} + +RLZ_DLL_EXPORT void ClearProductState( + rlz_lib::Product product, const rlz_lib::AccessPoint* access_points) { + return rlz_lib::ClearProductState(product, access_points); +} diff --git a/rlz/win/lib/lib_mutex.cc b/rlz/win/lib/lib_mutex.cc new file mode 100644 index 0000000..73dfade --- /dev/null +++ b/rlz/win/lib/lib_mutex.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Mutex to guarantee serialization of RLZ key accesses. + +#include "rlz/win/lib/lib_mutex.h" + +#include <windows.h> +#include <Sddl.h> // For SDDL_REVISION_1, ConvertStringSecurityDescript.. +#include <Aclapi.h> // For SetSecurityInfo + +#include "base/logging.h" +#include "base/win/windows_version.h" + +namespace { + +const wchar_t kMutexName[] = L"{A946A6A9-917E-4949-B9BC-6BADA8C7FD63}"; + +} // namespace anonymous + +namespace rlz_lib { + +// Needed to allow synchronization across integrity levels. +static bool SetObjectToLowIntegrity(HANDLE object, + SE_OBJECT_TYPE type = SE_KERNEL_OBJECT) { + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return true; // Not needed on XP. + + // The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity. + static const wchar_t kLowIntegritySddlSacl[] = L"S:(ML;;NW;;;LW)"; + + bool result = false; + DWORD error = ERROR_SUCCESS; + PSECURITY_DESCRIPTOR security_descriptor = NULL; + PACL sacl = NULL; + BOOL sacl_present = FALSE; + BOOL sacl_defaulted = FALSE; + + if (ConvertStringSecurityDescriptorToSecurityDescriptorW( + kLowIntegritySddlSacl, SDDL_REVISION_1, &security_descriptor, NULL)) { + if (GetSecurityDescriptorSacl(security_descriptor, &sacl_present, + &sacl, &sacl_defaulted)) { + error = SetSecurityInfo(object, type, LABEL_SECURITY_INFORMATION, + NULL, NULL, NULL, sacl); + result = (ERROR_SUCCESS == error); + } + LocalFree(security_descriptor); + } + + return result; +} + +LibMutex::LibMutex() : acquired_(false), mutex_(NULL) { + mutex_ = CreateMutex(NULL, false, kMutexName); + bool result = SetObjectToLowIntegrity(mutex_); + if (result) { + acquired_ = (WAIT_OBJECT_0 == WaitForSingleObject(mutex_, 5000L)); + } +} + +LibMutex::~LibMutex() { + if (acquired_) ReleaseMutex(mutex_); + CloseHandle(mutex_); +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/lib_mutex.h b/rlz/win/lib/lib_mutex.h new file mode 100644 index 0000000..6992bea --- /dev/null +++ b/rlz/win/lib/lib_mutex.h @@ -0,0 +1,28 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Mutex to guarantee serialization of RLZ key accesses. + +#ifndef RLZ_WIN_LIB_LIB_MUTEX_H_ +#define RLZ_WIN_LIB_LIB_MUTEX_H_ + +#include <windows.h> + +namespace rlz_lib { + +class LibMutex { + public: + LibMutex(); + ~LibMutex(); + + bool failed(void) { return !acquired_; } + + private: + bool acquired_; + HANDLE mutex_; +}; + +} // namespace rlz_lib + +#endif // RLZ_WIN_LIB_LIB_MUTEX_H_ diff --git a/rlz/win/lib/machine_deal.cc b/rlz/win/lib/machine_deal.cc new file mode 100644 index 0000000..3216260 --- /dev/null +++ b/rlz/win/lib/machine_deal.cc @@ -0,0 +1,300 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Library functions related to the OEM Deal Confirmation Code. + +#include "rlz/win/lib/machine_deal.h" + +#include <windows.h> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/string_split.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/win/registry.h" +#include "rlz/lib/assert.h" +#include "rlz/lib/lib_values.h" +#include "rlz/win/lib/lib_mutex.h" +#include "rlz/win/lib/registry_util.h" +#include "rlz/win/lib/rlz_value_store_registry.h" + +const wchar_t kDccValueName[] = L"DCC"; + +namespace { + +// Current DCC can only uses [a-zA-Z0-9_-!@$*();.<>,:] +// We will be more liberal and allow some additional chars, but not url meta +// chars. +bool IsGoodDccChar(char ch) { + if (IsAsciiAlpha(ch) || IsAsciiDigit(ch)) + return true; + + switch (ch) { + case '_': + case '-': + case '!': + case '@': + case '$': + case '*': + case '(': + case ')': + case ';': + case '.': + case '<': + case '>': + case ',': + case ':': + return true; + } + + return false; +} + +// This function will remove bad rlz chars and also limit the max rlz to some +// reasonable size. It also assumes that normalized_dcc is at least +// kMaxDccLength+1 long. +void NormalizeDcc(const char* raw_dcc, char* normalized_dcc) { + int index = 0; + for (; raw_dcc[index] != 0 && index < rlz_lib::kMaxDccLength; ++index) { + char current = raw_dcc[index]; + if (IsGoodDccChar(current)) { + normalized_dcc[index] = current; + } else { + normalized_dcc[index] = '.'; + } + } + + normalized_dcc[index] = 0; +} + +bool GetResponseLine(const char* response_text, int response_length, + int* search_index, std::string* response_line) { + if (!response_line || !search_index || *search_index > response_length) + return false; + + response_line->clear(); + + if (*search_index < 0) + return false; + + int line_begin = *search_index; + const char* line_end = strchr(response_text + line_begin, '\n'); + + if (line_end == NULL || line_end - response_text > response_length) { + line_end = response_text + response_length; + *search_index = -1; + } else { + *search_index = line_end - response_text + 1; + } + + response_line->assign(response_text + line_begin, + line_end - response_text - line_begin); + return true; +} + +bool GetResponseValue(const std::string& response_line, + const std::string& response_key, + std::string* value) { + if (!value) + return false; + + value->clear(); + + if (!StartsWithASCII(response_line, response_key, true)) + return false; + + std::vector<std::string> tokens; + base::SplitString(response_line, ':', &tokens); + if (tokens.size() != 2) + return false; + + // The first token is the key, the second is the value. The value is already + // trimmed for whitespace. + *value = tokens[1]; + return true; +} + +} // namespace anonymous + +namespace rlz_lib { + +bool MachineDealCode::Set(const char* dcc) { + LibMutex lock; + if (lock.failed()) + return false; + + // TODO: if (!ProcessInfo::CanWriteMachineKey()) return false; + + // Validate the new dcc value. + size_t length = strlen(dcc); + if (length > kMaxDccLength) { + ASSERT_STRING("MachineDealCode::Set: DCC length is exceeds max allowed."); + return false; + } + + base::win::RegKey hklm_key(HKEY_LOCAL_MACHINE, + RlzValueStoreRegistry::GetWideLibKeyName().c_str(), + KEY_READ | KEY_WRITE | KEY_WOW64_32KEY); + if (!hklm_key.Valid()) { + ASSERT_STRING("MachineDealCode::Set: Unable to create / open machine key." + " Did you call rlz_lib::CreateMachineState()?"); + return false; + } + + char normalized_dcc[kMaxDccLength + 1]; + NormalizeDcc(dcc, normalized_dcc); + VERIFY(length == strlen(normalized_dcc)); + + // Write the DCC to HKLM. Note that we need to include the null character + // when writing the string. + if (!RegKeyWriteValue(hklm_key, kDccValueName, normalized_dcc)) { + ASSERT_STRING("MachineDealCode::Set: Could not write the DCC value"); + return false; + } + + return true; +} + +bool MachineDealCode::GetNewCodeFromPingResponse(const char* response, + bool* has_new_dcc, char* new_dcc, int new_dcc_size) { + if (!has_new_dcc || !new_dcc || !new_dcc_size) + return false; + + *has_new_dcc = false; + new_dcc[0] = 0; + + int response_length = -1; + if (!IsPingResponseValid(response, &response_length)) + return false; + + // Get the current DCC value to compare to later) + char stored_dcc[kMaxDccLength + 1]; + if (!Get(stored_dcc, arraysize(stored_dcc))) + stored_dcc[0] = 0; + + int search_index = 0; + std::string response_line; + std::string new_dcc_value; + bool old_dcc_confirmed = false; + const std::string dcc_cgi(kDccCgiVariable); + const std::string dcc_cgi_response(kSetDccResponseVariable); + while (GetResponseLine(response, response_length, &search_index, + &response_line)) { + std::string value; + + if (!old_dcc_confirmed && + GetResponseValue(response_line, dcc_cgi, &value)) { + // This is the old DCC confirmation - should match value in registry. + if (value != stored_dcc) + return false; // Corrupted DCC - ignore this response. + else + old_dcc_confirmed = true; + continue; + } + + if (!(*has_new_dcc) && + GetResponseValue(response_line, dcc_cgi_response, &value)) { + // This is the new DCC. + if (value.size() > kMaxDccLength) continue; // Too long + *has_new_dcc = true; + new_dcc_value = value; + } + } + + old_dcc_confirmed |= (NULL == stored_dcc[0]); + + base::strlcpy(new_dcc, new_dcc_value.c_str(), new_dcc_size); + return old_dcc_confirmed; +} + +bool MachineDealCode::SetFromPingResponse(const char* response) { + bool has_new_dcc = false; + char new_dcc[kMaxDccLength + 1]; + + bool response_valid = GetNewCodeFromPingResponse( + response, &has_new_dcc, new_dcc, arraysize(new_dcc)); + + if (response_valid && has_new_dcc) + return Set(new_dcc); + + return response_valid; +} + +bool MachineDealCode::GetAsCgi(char* cgi, int cgi_size) { + if (!cgi || cgi_size <= 0) { + ASSERT_STRING("MachineDealCode::GetAsCgi: Invalid buffer"); + return false; + } + + cgi[0] = 0; + + std::string cgi_arg; + base::StringAppendF(&cgi_arg, "%s=", kDccCgiVariable); + int cgi_arg_length = cgi_arg.size(); + + if (cgi_arg_length >= cgi_size) { + ASSERT_STRING("MachineDealCode::GetAsCgi: Insufficient buffer size"); + return false; + } + + base::strlcpy(cgi, cgi_arg.c_str(), cgi_size); + + if (!Get(cgi + cgi_arg_length, cgi_size - cgi_arg_length)) { + cgi[0] = 0; + return false; + } + return true; +} + +bool MachineDealCode::Get(char* dcc, int dcc_size) { + LibMutex lock; + if (lock.failed()) + return false; + + if (!dcc || dcc_size <= 0) { + ASSERT_STRING("MachineDealCode::Get: Invalid buffer"); + return false; + } + + dcc[0] = 0; + + base::win::RegKey dcc_key(HKEY_LOCAL_MACHINE, + RlzValueStoreRegistry::GetWideLibKeyName().c_str(), + KEY_READ | KEY_WOW64_32KEY); + if (!dcc_key.Valid()) + return false; // no DCC key. + + size_t size = dcc_size; + if (!RegKeyReadValue(dcc_key, kDccValueName, dcc, &size)) { + ASSERT_STRING("MachineDealCode::Get: Insufficient buffer size"); + dcc[0] = 0; + return false; + } + + return true; +} + +bool MachineDealCode::Clear() { + base::win::RegKey dcc_key(HKEY_LOCAL_MACHINE, + RlzValueStoreRegistry::GetWideLibKeyName().c_str(), + KEY_READ | KEY_WRITE | KEY_WOW64_32KEY); + if (!dcc_key.Valid()) + return false; // no DCC key. + + dcc_key.DeleteValue(kDccValueName); + + // Verify deletion. + wchar_t dcc[kMaxDccLength + 1]; + DWORD dcc_size = arraysize(dcc); + if (dcc_key.ReadValue(kDccValueName, dcc, &dcc_size, NULL) == ERROR_SUCCESS) { + ASSERT_STRING("MachineDealCode::Clear: Could not delete the DCC value."); + return false; + } + + return true; +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/machine_deal.h b/rlz/win/lib/machine_deal.h new file mode 100644 index 0000000..5b8b84a --- /dev/null +++ b/rlz/win/lib/machine_deal.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Library functions related to the OEM Deal Confirmation Code. + +#ifndef RLZ_WIN_LIB_MACHINE_DEAL_H_ +#define RLZ_WIN_LIB_MACHINE_DEAL_H_ + +#include <string> +#include "rlz/win/lib/rlz_lib.h" + +namespace rlz_lib { + +class MachineDealCode { + public: + // Set the OEM Deal Confirmation Code (DCC). This information is used for RLZ + // initalization. Must have write access to HKLM - SYSTEM or admin, unless + // rlz_lib::CreateMachineState() has been successfully called. + static bool Set(const char* dcc); + + // Get the OEM Deal Confirmation Code from the registry. Used to ping + // the server. + static bool Get(AccessPoint point, + char* dcc, + int dcc_size, + const wchar_t* sid = NULL); + + // Parses a ping response, checks if it is valid and sets the machine DCC + // from the response. The response should also contain the current value of + // the DCC to be considered valid. + // Write access to HKLM (system / admin) needed, unless + // rlz_lib::CreateMachineState() has been successfully called. + static bool SetFromPingResponse(const char* response); + + // Gets the new DCC to set from a ping response. Returns true if the ping + // response is valid. Sets has_new_dcc true if there is a new DCC value. + static bool GetNewCodeFromPingResponse(const char* response, + bool* has_new_dcc, + char* new_dcc, + int new_dcc_size); + + // Get the DCC cgi argument string to append to a daily or financial ping. + static bool GetAsCgi(char* cgi, int cgi_size); + + // Get the machine code. + static bool Get(char* dcc, int dcc_size); + + protected: + // Clear the DCC value. Only for testing purposes. + // Requires write access to HKLM, unless rlz_lib::CreateMachineState() has + // been successfully called. + static bool Clear(); + + MachineDealCode() {} + ~MachineDealCode() {} +}; + +} // namespace rlz_lib + +#endif // RLZ_WIN_LIB_MACHINE_DEAL_H_ diff --git a/rlz/win/lib/machine_deal_test.cc b/rlz/win/lib/machine_deal_test.cc new file mode 100644 index 0000000..47b7265 --- /dev/null +++ b/rlz/win/lib/machine_deal_test.cc @@ -0,0 +1,156 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A test application for the MachineDealCode class. +// +// These tests should not be executed on the build server: +// - They assert for the failed cases. +// - They modify machine state (registry). +// +// These tests require write access to HKLM and HKCU, unless +// rlz_lib::CreateMachineState() has been successfully called. + +#include "base/logging.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "rlz/test/rlz_test_helpers.h" +#include "rlz/win/lib/machine_deal.h" + +class MachineDealCodeHelper : public rlz_lib::MachineDealCode { + public: + static bool Clear() { return rlz_lib::MachineDealCode::Clear(); } + + private: + MachineDealCodeHelper() {} + ~MachineDealCodeHelper() {} +}; + +class MachineDealCodeTest : public RlzLibTestBase { +}; + +TEST_F(MachineDealCodeTest, CreateMachineState) { + EXPECT_TRUE(rlz_lib::CreateMachineState()); +} + +TEST_F(MachineDealCodeTest, Set) { + MachineDealCodeHelper::Clear(); + char dcc_50[50]; + dcc_50[0] = 0; + + EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("dcc_value", dcc_50); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value_2")); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("dcc_value_2", dcc_50); +} + +TEST_F(MachineDealCodeTest, Get) { + MachineDealCodeHelper::Clear(); + char dcc_50[50], dcc_2[2]; + dcc_50[0] = 0; + dcc_2[0] = 0; + + EXPECT_FALSE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("dcc_value", dcc_50); + + EXPECT_FALSE(rlz_lib::MachineDealCode::Get(dcc_2, 2)); +} + +TEST_F(MachineDealCodeTest, SetFromPingResponse) { + rlz_lib::MachineDealCode::Set("MyDCCode"); + char dcc_50[50]; + + // Bad responses + + char* kBadDccResponse = + "dcc: NotMyDCCode \r\n" + "set_dcc: NewDCCode\r\n" + "crc32: 1B4D6BB3"; + EXPECT_FALSE(rlz_lib::MachineDealCode::SetFromPingResponse( + kBadDccResponse)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("MyDCCode", dcc_50); + + char* kBadCrcResponse = + "dcc: MyDCCode \r\n" + "set_dcc: NewDCCode\r\n" + "crc32: 90707106"; + EXPECT_FALSE(rlz_lib::MachineDealCode::SetFromPingResponse( + kBadCrcResponse)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("MyDCCode", dcc_50); + + // Good responses + + char* kMissingSetResponse = + "dcc: MyDCCode \r\n" + "crc32: 35F2E717"; + EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse( + kMissingSetResponse)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("MyDCCode", dcc_50); + + char* kGoodResponse = + "dcc: MyDCCode \r\n" + "set_dcc: NewDCCode\r\n" + "crc32: C8540E02"; + EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse( + kGoodResponse)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("NewDCCode", dcc_50); + + char* kGoodResponse2 = + "set_dcc: NewDCCode2 \r\n" + "dcc: NewDCCode \r\n" + "crc32: 60B6409A"; + EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse( + kGoodResponse2)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("NewDCCode2", dcc_50); + + MachineDealCodeHelper::Clear(); + char* kGoodResponse3 = + "set_dcc: NewDCCode \r\n" + "crc32: 374C1C47"; + EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse( + kGoodResponse3)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("NewDCCode", dcc_50); + + MachineDealCodeHelper::Clear(); + char* kGoodResponse4 = + "dcc: \r\n" + "set_dcc: NewDCCode \r\n" + "crc32: 0AB1FB39"; + EXPECT_TRUE(rlz_lib::MachineDealCode::SetFromPingResponse( + kGoodResponse4)); + EXPECT_TRUE(rlz_lib::MachineDealCode::Get(dcc_50, 50)); + EXPECT_STREQ("NewDCCode", dcc_50); +} + +TEST_F(MachineDealCodeTest, GetAsCgi) { + MachineDealCodeHelper::Clear(); + char cgi_50[50], cgi_2[2]; + cgi_50[0] = 0; + cgi_2[0] = 0; + + EXPECT_FALSE(rlz_lib::MachineDealCode::GetAsCgi(cgi_50, 50)); + EXPECT_STREQ("", cgi_50); + + EXPECT_TRUE(rlz_lib::MachineDealCode::Set("dcc_value")); + + EXPECT_TRUE(rlz_lib::MachineDealCode::GetAsCgi(cgi_50, 50)); + EXPECT_STREQ("dcc=dcc_value", cgi_50); + + EXPECT_FALSE(rlz_lib::MachineDealCode::GetAsCgi(cgi_2, 2)); +} diff --git a/rlz/win/lib/machine_id_win.cc b/rlz/win/lib/machine_id_win.cc new file mode 100644 index 0000000..8eb138a --- /dev/null +++ b/rlz/win/lib/machine_id_win.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> +#include <Sddl.h> // For ConvertSidToStringSidW. +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "rlz/lib/assert.h" + +namespace rlz_lib { + +namespace { + +bool GetSystemVolumeSerialNumber(int* number) { + if (!number) + return false; + + *number = 0; + + // Find the system root path (e.g: C:\). + wchar_t system_path[MAX_PATH + 1]; + if (!GetSystemDirectoryW(system_path, MAX_PATH)) + return false; + + wchar_t* first_slash = wcspbrk(system_path, L"\\/"); + if (first_slash != NULL) + *(first_slash + 1) = 0; + + DWORD number_local = 0; + if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, + NULL, 0)) + return false; + + *number = number_local; + return true; +} + +bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) { + static const DWORD kStartDomainLength = 128; // reasonable to start with + + scoped_array<wchar_t> domain_buffer(new wchar_t[kStartDomainLength]); + DWORD domain_size = kStartDomainLength; + DWORD sid_dword_size = sid_size; + SID_NAME_USE sid_name_use; + + BOOL success = ::LookupAccountNameW(NULL, account_name, sid, + &sid_dword_size, domain_buffer.get(), + &domain_size, &sid_name_use); + if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // We could have gotten the insufficient buffer error because + // one or both of sid and szDomain was too small. Check for that + // here. + if (sid_dword_size > sid_size) + return false; + + if (domain_size > kStartDomainLength) + domain_buffer.reset(new wchar_t[domain_size]); + + success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, + domain_buffer.get(), &domain_size, + &sid_name_use); + } + + return success != FALSE; +} + +std::wstring ConvertSidToString(SID* sid) { + std::wstring sid_string; +#if _WIN32_WINNT >= 0x500 + wchar_t* sid_buffer = NULL; + if (ConvertSidToStringSidW(sid, &sid_buffer)) { + sid_string = sid_buffer; + LocalFree(sid_buffer); + } +#else + SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid); + + if(sia->Value[0] || sia->Value[1]) { + base::SStringPrintf( + &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx", + SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1], + (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4], + (USHORT)sia->Value[5]); + } else { + ULONG authority = 0; + for (int i = 2; i < 6; ++i) { + authority <<= 8; + authority |= sia->Value[i]; + } + base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority); + } + + int sub_auth_count = *::GetSidSubAuthorityCount(sid); + for(int i = 0; i < sub_auth_count; ++i) + base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i)); +#endif + + return sid_string; +} + +} // namespace + +bool GetRawMachineId(string16* sid_string, int* volume_id) { + // Calculate the Windows SID. + + wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD size = arraysize(computer_name); + + if (GetComputerNameW(computer_name, &size)) { + char sid_buffer[SECURITY_MAX_SID_SIZE]; + SID* sid = reinterpret_cast<SID*>(sid_buffer); + if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) { + *sid_string = ConvertSidToString(sid); + } + } + + // Get the system drive volume serial number. + *volume_id = 0; + if (!GetSystemVolumeSerialNumber(volume_id)) { + ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number"); + *volume_id = 0; + } + + return true; +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/process_info.cc b/rlz/win/lib/process_info.cc new file mode 100644 index 0000000..8d4a02f --- /dev/null +++ b/rlz/win/lib/process_info.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Information about the current process. + +#include "rlz/win/lib/process_info.h" + +#include <windows.h> +#include <Sddl.h> // For ConvertSidToStringSid. +#include <LMCons.h> // For UNLEN + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/process_util.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" +#include "rlz/lib/assert.h" +#include "rlz/win/lib/vista_winnt.h" + +namespace { + +HRESULT GetCurrentUser(std::wstring* name, + std::wstring* domain, + std::wstring* sid) { + DWORD err; + + // Get the current username & domain the hard way. (GetUserNameEx would be + // nice, but unfortunately requires connectivity to a domain controller. + // Useless.) + + // (Following call doesn't work if running as a Service - because a Service + // runs under special accounts like LOCAL_SYSTEM, not as the logged in user. + // In which case, search for and use the process handle of a running + // Explorer.exe.) + HANDLE token; + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) + return E_FAIL; + + base::win::ScopedHandle scoped_process_token(token); + + // (Following call will fail with ERROR_INSUFFICIENT_BUFFER and give us the + // required size.) + scoped_array<char> token_user_bytes; + DWORD token_user_size; + DWORD token_user_size2; + BOOL result = ::GetTokenInformation(token, TokenUser, NULL, 0, + &token_user_size); + err = ::GetLastError(); + CHECK(!result && err == ERROR_INSUFFICIENT_BUFFER); + + token_user_bytes.reset(new char[token_user_size]); + if (!token_user_bytes.get()) + return E_OUTOFMEMORY; + + if (!::GetTokenInformation(token, TokenUser, token_user_bytes.get(), + token_user_size, &token_user_size2)) { + return E_FAIL; + } + + WCHAR user_name[UNLEN + 1]; // max username length + WCHAR domain_name[UNLEN + 1]; + DWORD user_name_size = UNLEN + 1; + DWORD domain_name_size = UNLEN + 1; + SID_NAME_USE sid_type; + TOKEN_USER* token_user = + reinterpret_cast<TOKEN_USER*>(token_user_bytes.get()); + if (!token_user) + return E_FAIL; + PSID user_sid = token_user->User.Sid; + if (!::LookupAccountSidW(NULL, user_sid, user_name, &user_name_size, + domain_name, &domain_name_size, &sid_type)) { + return E_FAIL; + } + + if (name != NULL) { + *name = user_name; + } + if (domain != NULL) { + *domain = domain_name; + } + if (sid != NULL) { + LPWSTR string_sid; + ConvertSidToStringSidW(user_sid, &string_sid); + *sid = string_sid; // copy out to cstring + // free memory, as documented for ConvertSidToStringSid + LocalFree(string_sid); + } + + return S_OK; +} + +HRESULT GetElevationType(PTOKEN_ELEVATION_TYPE elevation) { + if (!elevation) + return E_POINTER; + + *elevation = TokenElevationTypeDefault; + + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return E_FAIL; + + HANDLE process_token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &process_token)) + return HRESULT_FROM_WIN32(GetLastError()); + + base::win::ScopedHandle scoped_process_token(process_token); + + DWORD size; + TOKEN_ELEVATION_TYPE elevation_type; + if (!GetTokenInformation(process_token, TokenElevationType, &elevation_type, + sizeof(elevation_type), &size)) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + *elevation = elevation_type; + return S_OK; +} + +// based on http://msdn2.microsoft.com/en-us/library/aa376389.aspx +bool GetUserGroup(long* group) { + if (!group) + return false; + + *group = 0; + + // groups are listed in DECREASING order of importance + // (eg. If a user is a member of both the admin group and + // the power user group, it is more useful to list the user + // as an admin) + DWORD user_groups[] = {DOMAIN_ALIAS_RID_ADMINS, + DOMAIN_ALIAS_RID_POWER_USERS}; + SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY; + + for (int i = 0; i < arraysize(user_groups) && *group == 0; ++i) { + PSID current_group; + if (AllocateAndInitializeSid(&nt_authority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + user_groups[i], 0, 0, 0, 0, + 0, 0, ¤t_group)) { + BOOL current_level; + if (CheckTokenMembership(NULL, current_group, ¤t_level) && + current_level) { + *group = user_groups[i]; + } + + FreeSid(current_group); + } + } + + return group != 0; +} +} //anonymous + + +namespace rlz_lib { + +bool ProcessInfo::IsRunningAsSystem() { + static std::wstring name; + static std::wstring domain; + static std::wstring sid; + if (name.empty()) + CHECK(SUCCEEDED(GetCurrentUser(&name, &domain, &sid))); + + return (name == L"SYSTEM"); +} + +bool ProcessInfo::HasAdminRights() { + static bool evaluated = false; + static bool has_rights = false; + + if (!evaluated) { + if (IsRunningAsSystem()) { + has_rights = true; + } else if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + TOKEN_ELEVATION_TYPE elevation; + base::IntegrityLevel level; + + if (SUCCEEDED(GetElevationType(&elevation)) && + base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), &level)) + has_rights = (elevation == TokenElevationTypeFull) || + (level == HIGH_INTEGRITY); + } else { + long group = 0; + if (GetUserGroup(&group)) + has_rights = (group == DOMAIN_ALIAS_RID_ADMINS); + } + } + + evaluated = true; + if (!has_rights) + ASSERT_STRING("ProcessInfo::HasAdminRights: Does not have admin rights."); + + return has_rights; +} + +}; // namespace diff --git a/rlz/win/lib/process_info.h b/rlz/win/lib/process_info.h new file mode 100644 index 0000000..84bd604 --- /dev/null +++ b/rlz/win/lib/process_info.h @@ -0,0 +1,32 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Information about the current process. + +#ifndef RLZ_WIN_LIB_PROCESS_INFO_H_ +#define RLZ_WIN_LIB_PROCESS_INFO_H_ + +#include "base/basictypes.h" + +namespace rlz_lib { + +class ProcessInfo { + public: + enum IntegrityLevel { + INTEGRITY_UNKNOWN, + LOW_INTEGRITY, + MEDIUM_INTEGRITY, + HIGH_INTEGRITY, + }; + + // All these functions cache the result after first run. + static bool IsRunningAsSystem(); + static bool HasAdminRights(); // System / Admin / High Elevation on Vista + + private: + DISALLOW_COPY_AND_ASSIGN(ProcessInfo); +}; // class +}; // namespace + +#endif // RLZ_WIN_LIB_PROCESS_INFO_H_ diff --git a/rlz/win/lib/registry_util.cc b/rlz/win/lib/registry_util.cc new file mode 100644 index 0000000..6a324d5 --- /dev/null +++ b/rlz/win/lib/registry_util.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A helper library to keep track of a user's key by SID. +// Used by RLZ libary. Also to be used by SearchWithGoogle library. + +#include "rlz/win/lib/registry_util.h" + +#include "base/process_util.h" +#include "base/utf_string_conversions.h" +#include "base/win/registry.h" +#include "base/win/windows_version.h" +#include "rlz/lib/assert.h" +#include "rlz/win/lib/process_info.h" + +namespace rlz_lib { + +bool RegKeyReadValue(base::win::RegKey& key, const wchar_t* name, + char* value, size_t* value_size) { + value[0] = 0; + + std::wstring value_string; + if (key.ReadValue(name, &value_string) != ERROR_SUCCESS) { + return false; + } + + if (value_string.length() > *value_size) { + *value_size = value_string.length(); + return false; + } + + // Note that RLZ string are always ASCII by design. + strncpy(value, WideToUTF8(value_string).c_str(), *value_size); + value[*value_size - 1] = 0; + return true; +} + +bool RegKeyWriteValue(base::win::RegKey& key, const wchar_t* name, + const char* value) { + std::wstring value_string(ASCIIToWide(value)); + return key.WriteValue(name, value_string.c_str()) == ERROR_SUCCESS; +} + +bool HasUserKeyAccess(bool write_access) { + // The caller is trying to access HKEY_CURRENT_USER. Test to see if we can + // read from there. Don't try HKEY_CURRENT_USER because this will cause + // problems in the unit tests: if we open HKEY_CURRENT_USER directly here, + // the overriding done for unit tests will no longer work. So we try subkey + // "Software" which is known to always exist. + base::win::RegKey key; + if (key.Open(HKEY_CURRENT_USER, L"Software", KEY_READ) != ERROR_SUCCESS) + ASSERT_STRING("Could not open HKEY_CURRENT_USER"); + + if (ProcessInfo::IsRunningAsSystem()) { + ASSERT_STRING("UserKey::HasAccess: No access as SYSTEM without SID set."); + return false; + } + + if (write_access) { + if (base::win::GetVersion() < base::win::VERSION_VISTA) return true; + base::ProcessHandle process_handle = base::GetCurrentProcessHandle(); + base::IntegrityLevel level = base::INTEGRITY_UNKNOWN; + + if (!base::GetProcessIntegrityLevel(process_handle, &level)) { + ASSERT_STRING("UserKey::HasAccess: Cannot determine Integrity Level."); + return false; + } + if (level <= base::LOW_INTEGRITY) { + ASSERT_STRING("UserKey::HasAccess: Cannot write from Low Integrity."); + return false; + } + } + return true; +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/registry_util.h b/rlz/win/lib/registry_util.h new file mode 100644 index 0000000..60b8be6 --- /dev/null +++ b/rlz/win/lib/registry_util.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RLZ_WIN_LIB_REGISTRY_UTIL_H_ +#define RLZ_WIN_LIB_REGISTRY_UTIL_H_ + +namespace base { +namespace win { +class RegKey; +} // namespace win +} // namespace base + +namespace rlz_lib { + +bool RegKeyReadValue(base::win::RegKey& key, + const wchar_t* name, + char* value, + size_t* value_size); + +bool RegKeyWriteValue(base::win::RegKey& key, + const wchar_t* name, + const char* value); + +bool HasUserKeyAccess(bool write_access); + +} // namespace rlz_lib + +#endif // RLZ_WIN_LIB_REGISTRY_UTIL_H_ diff --git a/rlz/win/lib/rlz_lib.h b/rlz/win/lib/rlz_lib.h new file mode 100644 index 0000000..3adbf97 --- /dev/null +++ b/rlz/win/lib/rlz_lib.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A library to manage RLZ information for access-points shared +// across different client applications. +// +// All functions return true on success and false on error. +// This implemenation is thread safe. +// +// Each prototype mentions the registry access requirements: +// +// HKLM read: Will work from any process and at any privilege level on Vista. +// HKCU read: Calls made from the SYSTEM account must pass the current user's +// SID as the optional 'sid' param. Can be called from low integrity +// process on Vista. +// HKCU write: Calls made from the SYSTEM account must pass the current user's +// SID as the optional 'sid' param. Calls require at least medium +// integrity on Vista (e.g. Toolbar will need to use their broker) +// HKLM write: Calls must be made from an account with admin rights. No SID +// need be passed when running as SYSTEM. +// Functions which do not access registry will be marked with "no restrictions". + +#ifndef RLZ_WIN_LIB_RLZ_LIB_H_ +#define RLZ_WIN_LIB_RLZ_LIB_H_ + +// Clients can get away by just including rlz/lib/rlz_lib.h. This file only +// contains function definitions for files used by tests. It's mostly kept +// around for backwards-compatibility. + +#include "rlz/lib/rlz_lib.h" + +#include "base/win/registry.h" + +namespace rlz_lib { + +#if defined(OS_WIN) + +// Initialize temporary HKLM/HKCU registry hives used for testing. +// Testing RLZ requires reading and writing to the Windows registry. To keep +// the tests isolated from the machine's state, as well as to prevent the tests +// from causing side effects in the registry, HKCU and HKLM are overridden for +// the duration of the tests. RLZ tests don't expect the HKCU and KHLM hives to +// be empty though, and this function initializes the minimum value needed so +// that the test will run successfully. +// +// The two arguments to this function should be the keys that will represent +// the HKLM and HKCU registry hives during the tests. This function should be +// called *before* the hives are overridden. +void InitializeTempHivesForTesting(const base::win::RegKey& temp_hklm_key, + const base::win::RegKey& temp_hkcu_key); +#endif // defined(OS_WIN) + +} // namespace rlz_lib + +#endif // RLZ_WIN_LIB_RLZ_LIB_H_ diff --git a/rlz/win/lib/rlz_lib_win.cc b/rlz/win/lib/rlz_lib_win.cc new file mode 100644 index 0000000..e7b145e --- /dev/null +++ b/rlz/win/lib/rlz_lib_win.cc @@ -0,0 +1,260 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A library to manage RLZ information for access-points shared +// across different client applications. + +#include "rlz/win/lib/rlz_lib.h" + +#include <windows.h> +#include <aclapi.h> +#include <winerror.h> + +#include "base/basictypes.h" +#include "base/win/registry.h" +#include "base/win/windows_version.h" +#include "rlz/lib/assert.h" +#include "rlz/lib/rlz_value_store.h" +#include "rlz/win/lib/machine_deal.h" +#include "rlz/win/lib/rlz_value_store_registry.h" + +namespace { + +// Path to recursively copy into the replacemment hives. These are needed +// to make sure certain win32 APIs continue to run correctly once the real +// hives are replaced. +const wchar_t* kHKLMAccessProviders = + L"System\\CurrentControlSet\\Control\\Lsa\\AccessProviders"; + +// Helper functions + +void CopyRegistryTree(const base::win::RegKey& src, base::win::RegKey* dest) { + // First copy values. + for (base::win::RegistryValueIterator i(src.Handle(), L""); + i.Valid(); ++i) { + dest->WriteValue(i.Name(), reinterpret_cast<const void*>(i.Value()), + i.ValueSize(), i.Type()); + } + + // Next copy subkeys recursively. + for (base::win::RegistryKeyIterator i(src.Handle(), L""); + i.Valid(); ++i) { + base::win::RegKey subkey(dest->Handle(), i.Name(), KEY_ALL_ACCESS); + CopyRegistryTree(base::win::RegKey(src.Handle(), i.Name(), KEY_READ), + &subkey); + } +} + +} // namespace anonymous + + +namespace rlz_lib { + +// OEM Deal confirmation storage functions. + +template<class T> +class typed_buffer_ptr { + scoped_array<char> buffer_; + + public: + typed_buffer_ptr() { + } + + explicit typed_buffer_ptr(size_t size) : buffer_(new char[size]) { + } + + void reset(size_t size) { + buffer_.reset(new char[size]); + } + + operator T*() { + return reinterpret_cast<T*>(buffer_.get()); + } +}; + +// Check if this SID has the desired access by scanning the ACEs in the DACL. +// This function is part of the rlz_lib namespace so that it can be called from +// unit tests. Non-unit test code should not call this function. +bool HasAccess(PSID sid, ACCESS_MASK access_mask, ACL* dacl) { + if (dacl == NULL) + return false; + + ACL_SIZE_INFORMATION info; + if (!GetAclInformation(dacl, &info, sizeof(info), AclSizeInformation)) + return false; + + GENERIC_MAPPING generic_mapping = {KEY_READ, KEY_WRITE, KEY_EXECUTE, + KEY_ALL_ACCESS}; + MapGenericMask(&access_mask, &generic_mapping); + + for (DWORD i = 0; i < info.AceCount; ++i) { + ACCESS_ALLOWED_ACE* ace; + if (GetAce(dacl, i, reinterpret_cast<void**>(&ace))) { + if ((ace->Header.AceFlags & INHERIT_ONLY_ACE) == INHERIT_ONLY_ACE) + continue; + + PSID existing_sid = reinterpret_cast<PSID>(&ace->SidStart); + DWORD mask = ace->Mask; + MapGenericMask(&mask, &generic_mapping); + + if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && + (mask & access_mask) == access_mask && EqualSid(existing_sid, sid)) + return true; + + if (ace->Header.AceType == ACCESS_DENIED_ACE_TYPE && + (mask & access_mask) != 0 && EqualSid(existing_sid, sid)) + return false; + } + } + + return false; +} + +bool CreateMachineState() { + LibMutex lock; + if (lock.failed()) + return false; + + base::win::RegKey hklm_key; + if (hklm_key.Create(HKEY_LOCAL_MACHINE, + RlzValueStoreRegistry::GetWideLibKeyName().c_str(), + KEY_ALL_ACCESS | KEY_WOW64_32KEY) != ERROR_SUCCESS) { + ASSERT_STRING("rlz_lib::CreateMachineState: " + "Unable to create / open machine key."); + return false; + } + + // Create a SID that represents ALL USERS. + DWORD users_sid_size = SECURITY_MAX_SID_SIZE; + typed_buffer_ptr<SID> users_sid(users_sid_size); + CreateWellKnownSid(WinBuiltinUsersSid, NULL, users_sid, &users_sid_size); + + // Get the security descriptor for the registry key. + DWORD original_sd_size = 0; + ::RegGetKeySecurity(hklm_key.Handle(), DACL_SECURITY_INFORMATION, NULL, + &original_sd_size); + typed_buffer_ptr<SECURITY_DESCRIPTOR> original_sd(original_sd_size); + + LONG result = ::RegGetKeySecurity(hklm_key.Handle(), + DACL_SECURITY_INFORMATION, original_sd, &original_sd_size); + if (result != ERROR_SUCCESS) { + ASSERT_STRING("rlz_lib::CreateMachineState: " + "Unable to create / open machine key."); + return false; + } + + // Make a copy of the security descriptor so we can modify it. The one + // returned by RegGetKeySecurity() is self-relative, so we need to make it + // absolute. + DWORD new_sd_size = 0; + DWORD dacl_size = 0; + DWORD sacl_size = 0; + DWORD owner_size = 0; + DWORD group_size = 0; + ::MakeAbsoluteSD(original_sd, NULL, &new_sd_size, NULL, &dacl_size, + NULL, &sacl_size, NULL, &owner_size, + NULL, &group_size); + + typed_buffer_ptr<SECURITY_DESCRIPTOR> new_sd(new_sd_size); + // Make sure the DACL is big enough to add one more ACE. + typed_buffer_ptr<ACL> dacl(dacl_size + SECURITY_MAX_SID_SIZE); + typed_buffer_ptr<ACL> sacl(sacl_size); + typed_buffer_ptr<SID> owner(owner_size); + typed_buffer_ptr<SID> group(group_size); + + if (!::MakeAbsoluteSD(original_sd, new_sd, &new_sd_size, dacl, &dacl_size, + sacl, &sacl_size, owner, &owner_size, + group, &group_size)) { + ASSERT_STRING("rlz_lib::CreateMachineState: MakeAbsoluteSD failed"); + return false; + } + + // If all users already have read/write access to the registry key, then + // nothing to do. Otherwise change the security descriptor of the key to + // give everyone access. + if (HasAccess(users_sid, KEY_ALL_ACCESS, dacl)) { + return false; + } + + // Add ALL-USERS ALL-ACCESS ACL. + EXPLICIT_ACCESS ea; + ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); + ea.grfAccessPermissions = GENERIC_ALL | KEY_ALL_ACCESS; + ea.grfAccessMode = GRANT_ACCESS; + ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; + ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; + ea.Trustee.ptstrName = L"Everyone"; + + ACL* new_dacl = NULL; + result = SetEntriesInAcl(1, &ea, dacl, &new_dacl); + if (result != ERROR_SUCCESS) { + ASSERT_STRING("rlz_lib::CreateMachineState: SetEntriesInAcl failed"); + return false; + } + + BOOL ok = SetSecurityDescriptorDacl(new_sd, TRUE, new_dacl, FALSE); + if (!ok) { + ASSERT_STRING("rlz_lib::CreateMachineState: " + "SetSecurityDescriptorOwner failed"); + LocalFree(new_dacl); + return false; + } + + result = ::RegSetKeySecurity(hklm_key.Handle(), + DACL_SECURITY_INFORMATION, + new_sd); + // Note that the new DACL cannot be freed until after the call to + // RegSetKeySecurity(). + LocalFree(new_dacl); + + bool success = true; + if (result != ERROR_SUCCESS) { + ASSERT_STRING("rlz_lib::CreateMachineState: " + "Unable to create / open machine key."); + success = false; + } + + + return success; +} + +bool SetMachineDealCode(const char* dcc) { + return MachineDealCode::Set(dcc); +} + +bool GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size) { + return MachineDealCode::GetAsCgi(cgi, cgi_size); +} + +bool GetMachineDealCode(char* dcc, size_t dcc_size) { + return MachineDealCode::Get(dcc, dcc_size); +} + +// Combined functions. + +bool SetMachineDealCodeFromPingResponse(const char* response) { + return MachineDealCode::SetFromPingResponse(response); +} + +void InitializeTempHivesForTesting(const base::win::RegKey& temp_hklm_key, + const base::win::RegKey& temp_hkcu_key) { + // For the moment, the HKCU hive requires no initialization. + + if (base::win::GetVersion() >= base::win::VERSION_WIN7) { + // Copy the following HKLM subtrees to the temporary location so that the + // win32 APIs used by the tests continue to work: + // + // HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders + // + // This seems to be required since Win7. + base::win::RegKey dest(temp_hklm_key.Handle(), kHKLMAccessProviders, + KEY_ALL_ACCESS); + CopyRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE, + kHKLMAccessProviders, + KEY_READ), + &dest); + } +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/rlz_value_store_registry.cc b/rlz/win/lib/rlz_value_store_registry.cc new file mode 100644 index 0000000..36c53d5 --- /dev/null +++ b/rlz/win/lib/rlz_value_store_registry.cc @@ -0,0 +1,384 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "rlz/win/lib/rlz_value_store_registry.h" + +#include "base/win/registry.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "rlz/lib/assert.h" +#include "rlz/lib/lib_values.h" +#include "rlz/lib/rlz_lib.h" +#include "rlz/lib/string_utils.h" +#include "rlz/win/lib/registry_util.h" + +namespace rlz_lib { + +namespace { + +// +// Registry keys: +// +// RLZ's are stored as: +// <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName. +// +// Events are stored as: +// <AccessPointName><EventName> = 1 @ +// HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product). +// +// The OEM Deal Confirmation Code (DCC) is stored as +// kDccValueName = <DCC value> @ HKLM\kLibKeyName +// +// The last ping time, per product is stored as: +// GetProductName(product) = <last ping time> @ +// HKCU\kLibKeyName\kPingTimesSubkeyName. +// +// The server does not care about any of these constants. +// +const char kLibKeyName[] = "Software\\Google\\Common\\Rlz"; +const wchar_t kGoogleKeyName[] = L"Software\\Google"; +const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common"; +const char kRlzsSubkeyName[] = "RLZs"; +const char kEventsSubkeyName[] = "Events"; +const char kStatefulEventsSubkeyName[] = "StatefulEvents"; +const char kPingTimesSubkeyName[] = "PTimes"; + +std::wstring GetWideProductName(Product product) { + return ASCIIToWide(GetProductName(product)); +} + +void AppendBrandToString(std::string* str) { + std::string brand(SupplementaryBranding::GetBrand()); + if (!brand.empty()) + base::StringAppendF(str, "\\_%s", brand.c_str()); +} + +// Function to get the specific registry keys. +bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) { + std::string key_location; + base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name); + AppendBrandToString(&key_location); + + LONG ret = ERROR_SUCCESS; + if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { + ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), + access); + } else { + ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), + access); + } + + return ret == ERROR_SUCCESS; +} + +bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) { + return GetRegKey(kPingTimesSubkeyName, access, key); +} + + +bool GetEventsRegKey(const char* event_type, + const rlz_lib::Product* product, + REGSAM access, base::win::RegKey* key) { + std::string key_location; + base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, + event_type); + AppendBrandToString(&key_location); + + if (product != NULL) { + std::string product_name = GetProductName(*product); + if (product_name.empty()) + return false; + + base::StringAppendF(&key_location, "\\%s", product_name.c_str()); + } + + LONG ret = ERROR_SUCCESS; + if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { + ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), + access); + } else { + ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), + access); + } + + return ret == ERROR_SUCCESS; +} + +bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) { + return GetRegKey(kRlzsSubkeyName, access, key); +} + +bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) { + std::wstring product_name = GetWideProductName(product); + if (product_name.empty()) + return false; + + base::win::RegKey reg_key; + GetEventsRegKey(key, NULL, KEY_WRITE, ®_key); + reg_key.DeleteKey(product_name.c_str()); + + // Verify that the value no longer exists. + base::win::RegKey product_events( + reg_key.Handle(), product_name.c_str(), KEY_READ); + if (product_events.Valid()) { + ASSERT_STRING("ClearAllProductEvents: Key deletion failed"); + return false; + } + + return true; +} + +// Deletes a registry key if it exists and has no subkeys or values. +// TODO: Move this to a registry_utils file and add unittest. +bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) { + if (!key_name) { + ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL"); + return false; + } else { // Scope needed for RegKey + base::win::RegKey key(root_key, key_name, KEY_READ); + if (!key.Valid()) + return true; // Key does not exist - nothing to do. + + base::win::RegistryKeyIterator key_iter(root_key, key_name); + if (key_iter.SubkeyCount() > 0) + return true; // Not empty, so nothing to do + + base::win::RegistryValueIterator value_iter(root_key, key_name); + if (value_iter.ValueCount() > 0) + return true; // Not empty, so nothing to do + } + + // The key is empty - delete it now. + base::win::RegKey key(root_key, L"", KEY_WRITE); + return key.DeleteKey(key_name) == ERROR_SUCCESS; +} + +} // namespace + +// static +std::wstring RlzValueStoreRegistry::GetWideLibKeyName() { + return ASCIIToWide(kLibKeyName); +} + +bool RlzValueStoreRegistry::HasAccess(AccessType type) { + return HasUserKeyAccess(type == kWriteAccess); +} + +bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) { + base::win::RegKey key; + std::wstring product_name = GetWideProductName(product); + return GetPingTimesRegKey(KEY_WRITE, &key) && + key.WriteValue(product_name.c_str(), &time, sizeof(time), + REG_QWORD) == ERROR_SUCCESS; +} + +bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) { + base::win::RegKey key; + std::wstring product_name = GetWideProductName(product); + return GetPingTimesRegKey(KEY_READ, &key) && + key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS; +} + +bool RlzValueStoreRegistry::ClearPingTime(Product product) { + base::win::RegKey key; + GetPingTimesRegKey(KEY_WRITE, &key); + + std::wstring product_name = GetWideProductName(product); + key.DeleteValue(product_name.c_str()); + + // Verify deletion. + uint64 value; + DWORD size = sizeof(value); + if (key.ReadValue( + product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) { + ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete."); + return false; + } + + return true; +} + +bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point, + const char* new_rlz) { + const char* access_point_name = GetAccessPointName(access_point); + if (!access_point_name) + return false; + + std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); + base::win::RegKey key; + GetAccessPointRlzsRegKey(KEY_WRITE, &key); + + if (!RegKeyWriteValue(key, access_point_name_wide.c_str(), new_rlz)) { + ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value"); + return false; + } + return true; +} + +bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point, + char* rlz, + size_t rlz_size) { + const char* access_point_name = GetAccessPointName(access_point); + if (!access_point_name) + return false; + + size_t size = rlz_size; + base::win::RegKey key; + GetAccessPointRlzsRegKey(KEY_READ, &key); + if (!RegKeyReadValue(key, ASCIIToWide(access_point_name).c_str(), + rlz, &size)) { + rlz[0] = 0; + if (size > rlz_size) { + ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size"); + return false; + } + } + return true; +} + +bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) { + const char* access_point_name = GetAccessPointName(access_point); + if (!access_point_name) + return false; + + std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); + base::win::RegKey key; + GetAccessPointRlzsRegKey(KEY_WRITE, &key); + + key.DeleteValue(access_point_name_wide.c_str()); + + // Verify deletion. + DWORD value; + if (key.ReadValueDW(access_point_name_wide.c_str(), &value) == + ERROR_SUCCESS) { + ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value."); + return false; + } + return true; +} + +bool RlzValueStoreRegistry::AddProductEvent(Product product, + const char* event_rlz) { + std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); + base::win::RegKey reg_key; + GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, ®_key); + if (reg_key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { + ASSERT_STRING("AddProductEvent: Could not write the new event value"); + return false; + } + + return true; +} + +bool RlzValueStoreRegistry::ReadProductEvents(Product product, + std::vector<std::string>* events) { + // Open the events key. + base::win::RegKey events_key; + GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key); + if (!events_key.Valid()) + return false; + + // Append the events to the buffer. + int num_values = 0; + LONG result = ERROR_SUCCESS; + for (num_values = 0; result == ERROR_SUCCESS; ++num_values) { + // Max 32767 bytes according to MSDN, but we never use that much. + const size_t kMaxValueNameLength = 2048; + char buffer[kMaxValueNameLength]; + DWORD size = arraysize(buffer); + + result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size, + NULL, NULL, NULL, NULL); + if (result == ERROR_SUCCESS) + events->push_back(std::string(buffer)); + } + + return result == ERROR_NO_MORE_ITEMS; +} + +bool RlzValueStoreRegistry::ClearProductEvent(Product product, + const char* event_rlz) { + std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); + base::win::RegKey key; + GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key); + key.DeleteValue(event_rlz_wide.c_str()); + + // Verify deletion. + DWORD value; + if (key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS) { + ASSERT_STRING("ClearProductEvent: Could not delete the event value."); + return false; + } + + return true; +} + +bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) { + return ClearAllProductEventValues(product, kEventsSubkeyName); +} + +bool RlzValueStoreRegistry::AddStatefulEvent(Product product, + const char* event_rlz) { + base::win::RegKey key; + std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); + if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) || + key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { + ASSERT_STRING( + "AddStatefulEvent: Could not write the new stateful event"); + return false; + } + + return true; +} + +bool RlzValueStoreRegistry::IsStatefulEvent(Product product, + const char* event_rlz) { + DWORD value; + base::win::RegKey key; + GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key); + std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); + return key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS; +} + +bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) { + return ClearAllProductEventValues(product, kStatefulEventsSubkeyName); +} + +void RlzValueStoreRegistry::CollectGarbage() { + // Delete each of the known subkeys if empty. + const char* subkeys[] = { + kRlzsSubkeyName, + kEventsSubkeyName, + kStatefulEventsSubkeyName, + kPingTimesSubkeyName + }; + + for (int i = 0; i < arraysize(subkeys); i++) { + std::string subkey_name; + base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]); + AppendBrandToString(&subkey_name); + + VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, + ASCIIToWide(subkey_name).c_str())); + } + + // Delete the library key and its parents too now if empty. + VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str())); + VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName)); + VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName)); +} + +ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() { + if (!lock_.failed()) + store_.reset(new RlzValueStoreRegistry); +} + +ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() { +} + +RlzValueStore* ScopedRlzValueStoreLock::GetStore() { + return store_.get(); +} + +} // namespace rlz_lib diff --git a/rlz/win/lib/rlz_value_store_registry.h b/rlz/win/lib/rlz_value_store_registry.h new file mode 100644 index 0000000..c7fae46 --- /dev/null +++ b/rlz/win/lib/rlz_value_store_registry.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_ +#define RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_ + +#include "base/compiler_specific.h" +#include "rlz/lib/rlz_value_store.h" + +namespace rlz_lib { + +// Implements RlzValueStore by storing values in the windows registry. +class RlzValueStoreRegistry : public RlzValueStore { + public: + static std::wstring GetWideLibKeyName(); + + virtual bool HasAccess(AccessType type) OVERRIDE; + + virtual bool WritePingTime(Product product, int64 time) OVERRIDE; + virtual bool ReadPingTime(Product product, int64* time) OVERRIDE; + virtual bool ClearPingTime(Product product) OVERRIDE; + + virtual bool WriteAccessPointRlz(AccessPoint access_point, + const char* new_rlz) OVERRIDE; + virtual bool ReadAccessPointRlz(AccessPoint access_point, + char* rlz, + size_t rlz_size) OVERRIDE; + virtual bool ClearAccessPointRlz(AccessPoint access_point) OVERRIDE; + + virtual bool AddProductEvent(Product product, const char* event_rlz) OVERRIDE; + virtual bool ReadProductEvents(Product product, + std::vector<std::string>* events) OVERRIDE; + virtual bool ClearProductEvent(Product product, + const char* event_rlz) OVERRIDE; + virtual bool ClearAllProductEvents(Product product) OVERRIDE; + + virtual bool AddStatefulEvent(Product product, + const char* event_rlz) OVERRIDE; + virtual bool IsStatefulEvent(Product product, + const char* event_rlz) OVERRIDE; + virtual bool ClearAllStatefulEvents(Product product) OVERRIDE; + + virtual void CollectGarbage() OVERRIDE; + + private: + RlzValueStoreRegistry() {} + DISALLOW_COPY_AND_ASSIGN(RlzValueStoreRegistry); + friend class ScopedRlzValueStoreLock; +}; + +} // namespace rlz_lib + +#endif // RLZ_WIN_LIB_RLZ_VALUE_STORE_REGISTRY_H_ + diff --git a/rlz/win/lib/vista_winnt.h b/rlz/win/lib/vista_winnt.h new file mode 100644 index 0000000..073e66f --- /dev/null +++ b/rlz/win/lib/vista_winnt.h @@ -0,0 +1,99 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains snippets borrowed from the Vista SDK version of +// WinNT.h, (c) Microsoft (2006) + +#ifndef RLZ_WIN_LIB_VISTA_WINNT_H_ +#define RLZ_WIN_LIB_VISTA_WINNT_H_ + +#include <windows.h> + +// If no Vista SDK yet, borrow these from Vista's version of WinNT.h +#ifndef SE_GROUP_INTEGRITY + +// TOKEN_MANDATORY_LABEL.Label.Attributes = SE_GROUP_INTEGRITY +#define SE_GROUP_INTEGRITY (0x00000020L) +#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L) + +typedef struct _TOKEN_MANDATORY_LABEL { + SID_AND_ATTRIBUTES Label; +} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL; + +// These are a few new enums for TOKEN_INFORMATION_CLASS +#define TokenElevationType static_cast<TOKEN_INFORMATION_CLASS>(18) +#define TokenLinkedToken static_cast<TOKEN_INFORMATION_CLASS>(19) +#define TokenElevation static_cast<TOKEN_INFORMATION_CLASS>(20) +#define TokenHasRestrictions static_cast<TOKEN_INFORMATION_CLASS>(21) +#define TokenAccessInformation static_cast<TOKEN_INFORMATION_CLASS>(22) +#define TokenVirtualizationAllowed static_cast<TOKEN_INFORMATION_CLASS>(23) +#define TokenVirtualizationEnabled static_cast<TOKEN_INFORMATION_CLASS>(24) +// TokenIntegrityLevel is the proces's privilege level, low, med, or high +#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(25) +// TokenIntegrityLevelDeasktop is an alternate level used for access apis +// (screen readers, imes) +#define TokenIntegrityLevelDesktop static_cast<TOKEN_INFORMATION_CLASS>(26) + +// This is a new flag to pass to GetNamedSecurityInfo or SetNamedSecurityInfo +// that puts the mandatory level label info in an access control list (ACL) +// structure in the parameter normally used for system acls (SACL) +#define LABEL_SECURITY_INFORMATION (0x00000010L) + +// The new Access Control Entry type identifier for mandatory labels +#define SYSTEM_MANDATORY_LABEL_ACE_TYPE (0x11) + +// The structure of mandatory label acess control binary entry +typedef struct _SYSTEM_MANDATORY_LABEL_ACE { + ACE_HEADER Header; + ACCESS_MASK Mask; + DWORD SidStart; +} SYSTEM_MANDATORY_LABEL_ACE, *PSYSTEM_MANDATORY_LABEL_ACE; + +// Masks for ACCESS_MASK above +#define SYSTEM_MANDATORY_LABEL_NO_WRITE_UP 0x1 +#define SYSTEM_MANDATORY_LABEL_NO_READ_UP 0x2 +#define SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP 0x4 +#define SYSTEM_MANDATORY_LABEL_VALID_MASK \ + (SYSTEM_MANDATORY_LABEL_NO_WRITE_UP | \ + SYSTEM_MANDATORY_LABEL_NO_READ_UP | \ + SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP) + +// The SID authority for mandatory labels +#define SECURITY_MANDATORY_LABEL_AUTHORITY {0, 0, 0, 0, 0, 16} + +// the RID values (sub authorities) that define mandatory label levels +#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L) +#define SECURITY_MANDATORY_LOW_RID (0x00001000L) +#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L) +#define SECURITY_MANDATORY_HIGH_RID (0x00003000L) +#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L) +#define SECURITY_MANDATORY_UI_ACCESS_RID (0x00004100L) +#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L) + +// Vista's mandatory labels, enumerated +typedef enum _MANDATORY_LEVEL { + MandatoryLevelUntrusted = 0, + MandatoryLevelLow, + MandatoryLevelMedium, + MandatoryLevelHigh, + MandatoryLevelSystem, + MandatoryLevelSecureProcess, + MandatoryLevelCount +} MANDATORY_LEVEL, *PMANDATORY_LEVEL; + + +// Token elevation values describe the relative strength of a given token. +// A full token is a token with all groups and privileges to which the +// principal is authorized. A limited token is one with some groups or +// privileges removed. + +typedef enum _TOKEN_ELEVATION_TYPE { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited, +} TOKEN_ELEVATION_TYPE, *PTOKEN_ELEVATION_TYPE; + +#endif // #ifndef SE_GROUP_INTEGRITY + +#endif // RLZ_WIN_LIB_VISTA_WINNT_H_ |