1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "rlz/win/lib/rlz_value_store_registry.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "base/win/registry.h" 10 #include "rlz/lib/assert.h" 11 #include "rlz/lib/lib_values.h" 12 #include "rlz/lib/rlz_lib.h" 13 #include "rlz/lib/string_utils.h" 14 #include "rlz/win/lib/registry_util.h" 15 16 using base::ASCIIToWide; 17 18 namespace rlz_lib { 19 20 namespace { 21 22 // 23 // Registry keys: 24 // 25 // RLZ's are stored as: 26 // <AccessPointName> = <RLZ value> @ kRootKey\kLibKeyName\kRlzsSubkeyName. 27 // 28 // Events are stored as: 29 // <AccessPointName><EventName> = 1 @ 30 // HKCU\kLibKeyName\kEventsSubkeyName\GetProductName(product). 31 // 32 // The OEM Deal Confirmation Code (DCC) is stored as 33 // kDccValueName = <DCC value> @ HKLM\kLibKeyName 34 // 35 // The last ping time, per product is stored as: 36 // GetProductName(product) = <last ping time> @ 37 // HKCU\kLibKeyName\kPingTimesSubkeyName. 38 // 39 // The server does not care about any of these constants. 40 // 41 const char kLibKeyName[] = "Software\\Google\\Common\\Rlz"; 42 const wchar_t kGoogleKeyName[] = L"Software\\Google"; 43 const wchar_t kGoogleCommonKeyName[] = L"Software\\Google\\Common"; 44 const char kRlzsSubkeyName[] = "RLZs"; 45 const char kEventsSubkeyName[] = "Events"; 46 const char kStatefulEventsSubkeyName[] = "StatefulEvents"; 47 const char kPingTimesSubkeyName[] = "PTimes"; 48 49 std::wstring GetWideProductName(Product product) { 50 return ASCIIToWide(GetProductName(product)); 51 } 52 53 void AppendBrandToString(std::string* str) { 54 std::string brand(SupplementaryBranding::GetBrand()); 55 if (!brand.empty()) 56 base::StringAppendF(str, "\\_%s", brand.c_str()); 57 } 58 59 // Function to get the specific registry keys. 60 bool GetRegKey(const char* name, REGSAM access, base::win::RegKey* key) { 61 std::string key_location; 62 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, name); 63 AppendBrandToString(&key_location); 64 65 LONG ret = ERROR_SUCCESS; 66 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { 67 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), 68 access); 69 } else { 70 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), 71 access); 72 } 73 74 return ret == ERROR_SUCCESS; 75 } 76 77 bool GetPingTimesRegKey(REGSAM access, base::win::RegKey* key) { 78 return GetRegKey(kPingTimesSubkeyName, access, key); 79 } 80 81 82 bool GetEventsRegKey(const char* event_type, 83 const rlz_lib::Product* product, 84 REGSAM access, base::win::RegKey* key) { 85 std::string key_location; 86 base::StringAppendF(&key_location, "%s\\%s", kLibKeyName, 87 event_type); 88 AppendBrandToString(&key_location); 89 90 if (product != NULL) { 91 std::string product_name = GetProductName(*product); 92 if (product_name.empty()) 93 return false; 94 95 base::StringAppendF(&key_location, "\\%s", product_name.c_str()); 96 } 97 98 LONG ret = ERROR_SUCCESS; 99 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { 100 ret = key->Create(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), 101 access); 102 } else { 103 ret = key->Open(HKEY_CURRENT_USER, ASCIIToWide(key_location).c_str(), 104 access); 105 } 106 107 return ret == ERROR_SUCCESS; 108 } 109 110 bool GetAccessPointRlzsRegKey(REGSAM access, base::win::RegKey* key) { 111 return GetRegKey(kRlzsSubkeyName, access, key); 112 } 113 114 bool ClearAllProductEventValues(rlz_lib::Product product, const char* key) { 115 std::wstring product_name = GetWideProductName(product); 116 if (product_name.empty()) 117 return false; 118 119 base::win::RegKey reg_key; 120 GetEventsRegKey(key, NULL, KEY_WRITE, ®_key); 121 reg_key.DeleteKey(product_name.c_str()); 122 123 // Verify that the value no longer exists. 124 base::win::RegKey product_events( 125 reg_key.Handle(), product_name.c_str(), KEY_READ); 126 if (product_events.Valid()) { 127 ASSERT_STRING("ClearAllProductEvents: Key deletion failed"); 128 return false; 129 } 130 131 return true; 132 } 133 134 // Deletes a registry key if it exists and has no subkeys or values. 135 // TODO: Move this to a registry_utils file and add unittest. 136 bool DeleteKeyIfEmpty(HKEY root_key, const wchar_t* key_name) { 137 if (!key_name) { 138 ASSERT_STRING("DeleteKeyIfEmpty: key_name is NULL"); 139 return false; 140 } else { // Scope needed for RegKey 141 base::win::RegKey key(root_key, key_name, KEY_READ); 142 if (!key.Valid()) 143 return true; // Key does not exist - nothing to do. 144 145 base::win::RegistryKeyIterator key_iter(root_key, key_name); 146 if (key_iter.SubkeyCount() > 0) 147 return true; // Not empty, so nothing to do 148 149 base::win::RegistryValueIterator value_iter(root_key, key_name); 150 if (value_iter.ValueCount() > 0) 151 return true; // Not empty, so nothing to do 152 } 153 154 // The key is empty - delete it now. 155 base::win::RegKey key(root_key, L"", KEY_WRITE); 156 return key.DeleteKey(key_name) == ERROR_SUCCESS; 157 } 158 159 } // namespace 160 161 // static 162 std::wstring RlzValueStoreRegistry::GetWideLibKeyName() { 163 return ASCIIToWide(kLibKeyName); 164 } 165 166 bool RlzValueStoreRegistry::HasAccess(AccessType type) { 167 return HasUserKeyAccess(type == kWriteAccess); 168 } 169 170 bool RlzValueStoreRegistry::WritePingTime(Product product, int64 time) { 171 base::win::RegKey key; 172 std::wstring product_name = GetWideProductName(product); 173 return GetPingTimesRegKey(KEY_WRITE, &key) && 174 key.WriteValue(product_name.c_str(), &time, sizeof(time), 175 REG_QWORD) == ERROR_SUCCESS; 176 } 177 178 bool RlzValueStoreRegistry::ReadPingTime(Product product, int64* time) { 179 base::win::RegKey key; 180 std::wstring product_name = GetWideProductName(product); 181 return GetPingTimesRegKey(KEY_READ, &key) && 182 key.ReadInt64(product_name.c_str(), time) == ERROR_SUCCESS; 183 } 184 185 bool RlzValueStoreRegistry::ClearPingTime(Product product) { 186 base::win::RegKey key; 187 GetPingTimesRegKey(KEY_WRITE, &key); 188 189 std::wstring product_name = GetWideProductName(product); 190 key.DeleteValue(product_name.c_str()); 191 192 // Verify deletion. 193 uint64 value; 194 DWORD size = sizeof(value); 195 if (key.ReadValue( 196 product_name.c_str(), &value, &size, NULL) == ERROR_SUCCESS) { 197 ASSERT_STRING("RlzValueStoreRegistry::ClearPingTime: Failed to delete."); 198 return false; 199 } 200 201 return true; 202 } 203 204 bool RlzValueStoreRegistry::WriteAccessPointRlz(AccessPoint access_point, 205 const char* new_rlz) { 206 const char* access_point_name = GetAccessPointName(access_point); 207 if (!access_point_name) 208 return false; 209 210 std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); 211 base::win::RegKey key; 212 GetAccessPointRlzsRegKey(KEY_WRITE, &key); 213 214 if (!RegKeyWriteValue(key, access_point_name_wide.c_str(), new_rlz)) { 215 ASSERT_STRING("SetAccessPointRlz: Could not write the new RLZ value"); 216 return false; 217 } 218 return true; 219 } 220 221 bool RlzValueStoreRegistry::ReadAccessPointRlz(AccessPoint access_point, 222 char* rlz, 223 size_t rlz_size) { 224 const char* access_point_name = GetAccessPointName(access_point); 225 if (!access_point_name) 226 return false; 227 228 size_t size = rlz_size; 229 base::win::RegKey key; 230 GetAccessPointRlzsRegKey(KEY_READ, &key); 231 if (!RegKeyReadValue(key, ASCIIToWide(access_point_name).c_str(), 232 rlz, &size)) { 233 rlz[0] = 0; 234 if (size > rlz_size) { 235 ASSERT_STRING("GetAccessPointRlz: Insufficient buffer size"); 236 return false; 237 } 238 } 239 return true; 240 } 241 242 bool RlzValueStoreRegistry::ClearAccessPointRlz(AccessPoint access_point) { 243 const char* access_point_name = GetAccessPointName(access_point); 244 if (!access_point_name) 245 return false; 246 247 std::wstring access_point_name_wide(ASCIIToWide(access_point_name)); 248 base::win::RegKey key; 249 GetAccessPointRlzsRegKey(KEY_WRITE, &key); 250 251 key.DeleteValue(access_point_name_wide.c_str()); 252 253 // Verify deletion. 254 DWORD value; 255 if (key.ReadValueDW(access_point_name_wide.c_str(), &value) == 256 ERROR_SUCCESS) { 257 ASSERT_STRING("SetAccessPointRlz: Could not clear the RLZ value."); 258 return false; 259 } 260 return true; 261 } 262 263 bool RlzValueStoreRegistry::AddProductEvent(Product product, 264 const char* event_rlz) { 265 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); 266 base::win::RegKey reg_key; 267 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, ®_key); 268 if (reg_key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { 269 ASSERT_STRING("AddProductEvent: Could not write the new event value"); 270 return false; 271 } 272 273 return true; 274 } 275 276 bool RlzValueStoreRegistry::ReadProductEvents(Product product, 277 std::vector<std::string>* events) { 278 // Open the events key. 279 base::win::RegKey events_key; 280 GetEventsRegKey(kEventsSubkeyName, &product, KEY_READ, &events_key); 281 if (!events_key.Valid()) 282 return false; 283 284 // Append the events to the buffer. 285 int num_values = 0; 286 LONG result = ERROR_SUCCESS; 287 for (num_values = 0; result == ERROR_SUCCESS; ++num_values) { 288 // Max 32767 bytes according to MSDN, but we never use that much. 289 const size_t kMaxValueNameLength = 2048; 290 char buffer[kMaxValueNameLength]; 291 DWORD size = arraysize(buffer); 292 293 result = RegEnumValueA(events_key.Handle(), num_values, buffer, &size, 294 NULL, NULL, NULL, NULL); 295 if (result == ERROR_SUCCESS) 296 events->push_back(std::string(buffer)); 297 } 298 299 return result == ERROR_NO_MORE_ITEMS; 300 } 301 302 bool RlzValueStoreRegistry::ClearProductEvent(Product product, 303 const char* event_rlz) { 304 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); 305 base::win::RegKey key; 306 GetEventsRegKey(kEventsSubkeyName, &product, KEY_WRITE, &key); 307 key.DeleteValue(event_rlz_wide.c_str()); 308 309 // Verify deletion. 310 DWORD value; 311 if (key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS) { 312 ASSERT_STRING("ClearProductEvent: Could not delete the event value."); 313 return false; 314 } 315 316 return true; 317 } 318 319 bool RlzValueStoreRegistry::ClearAllProductEvents(Product product) { 320 return ClearAllProductEventValues(product, kEventsSubkeyName); 321 } 322 323 bool RlzValueStoreRegistry::AddStatefulEvent(Product product, 324 const char* event_rlz) { 325 base::win::RegKey key; 326 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); 327 if (!GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_WRITE, &key) || 328 key.WriteValue(event_rlz_wide.c_str(), 1) != ERROR_SUCCESS) { 329 ASSERT_STRING( 330 "AddStatefulEvent: Could not write the new stateful event"); 331 return false; 332 } 333 334 return true; 335 } 336 337 bool RlzValueStoreRegistry::IsStatefulEvent(Product product, 338 const char* event_rlz) { 339 DWORD value; 340 base::win::RegKey key; 341 GetEventsRegKey(kStatefulEventsSubkeyName, &product, KEY_READ, &key); 342 std::wstring event_rlz_wide(ASCIIToWide(event_rlz)); 343 return key.ReadValueDW(event_rlz_wide.c_str(), &value) == ERROR_SUCCESS; 344 } 345 346 bool RlzValueStoreRegistry::ClearAllStatefulEvents(Product product) { 347 return ClearAllProductEventValues(product, kStatefulEventsSubkeyName); 348 } 349 350 void RlzValueStoreRegistry::CollectGarbage() { 351 // Delete each of the known subkeys if empty. 352 const char* subkeys[] = { 353 kRlzsSubkeyName, 354 kEventsSubkeyName, 355 kStatefulEventsSubkeyName, 356 kPingTimesSubkeyName 357 }; 358 359 for (int i = 0; i < arraysize(subkeys); i++) { 360 std::string subkey_name; 361 base::StringAppendF(&subkey_name, "%s\\%s", kLibKeyName, subkeys[i]); 362 AppendBrandToString(&subkey_name); 363 364 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, 365 ASCIIToWide(subkey_name).c_str())); 366 } 367 368 // Delete the library key and its parents too now if empty. 369 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, GetWideLibKeyName().c_str())); 370 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleCommonKeyName)); 371 VERIFY(DeleteKeyIfEmpty(HKEY_CURRENT_USER, kGoogleKeyName)); 372 } 373 374 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() { 375 if (!lock_.failed()) 376 store_.reset(new RlzValueStoreRegistry); 377 } 378 379 ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() { 380 } 381 382 RlzValueStore* ScopedRlzValueStoreLock::GetStore() { 383 return store_.get(); 384 } 385 386 } // namespace rlz_lib 387