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