Home | History | Annotate | Download | only in lib
      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, &reg_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, &reg_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