• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "remoting/host/pairing_registry_delegate_win.h"
6 
7 #include "base/json/json_string_value_serializer.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "base/win/registry.h"
12 
13 namespace remoting {
14 
15 namespace {
16 
17 // Duplicates a registry key handle (returned by RegCreateXxx/RegOpenXxx).
18 // The returned handle cannot be inherited and has the same permissions as
19 // the source one.
DuplicateKeyHandle(HKEY source,base::win::RegKey * dest)20 bool DuplicateKeyHandle(HKEY source, base::win::RegKey* dest) {
21   HANDLE handle;
22   if (!DuplicateHandle(GetCurrentProcess(),
23                        source,
24                        GetCurrentProcess(),
25                        &handle,
26                        0,
27                        FALSE,
28                        DUPLICATE_SAME_ACCESS)) {
29     PLOG(ERROR) << "Failed to duplicate a registry key handle";
30     return false;
31   }
32 
33   dest->Set(reinterpret_cast<HKEY>(handle));
34   return true;
35 }
36 
37 // Reads value |value_name| from |key| as a JSON string and returns it as
38 // |base::Value|.
ReadValue(const base::win::RegKey & key,const wchar_t * value_name)39 scoped_ptr<base::DictionaryValue> ReadValue(const base::win::RegKey& key,
40                                             const wchar_t* value_name) {
41   // presubmit: allow wstring
42   std::wstring value_json;
43   LONG result = key.ReadValue(value_name, &value_json);
44   if (result != ERROR_SUCCESS) {
45     SetLastError(result);
46     PLOG(ERROR) << "Cannot read value '" << value_name << "'";
47     return scoped_ptr<base::DictionaryValue>();
48   }
49 
50   // Parse the value.
51   std::string value_json_utf8 = base::WideToUTF8(value_json);
52   JSONStringValueSerializer serializer(&value_json_utf8);
53   int error_code;
54   std::string error_message;
55   scoped_ptr<base::Value> value(serializer.Deserialize(&error_code,
56                                                        &error_message));
57   if (!value) {
58     LOG(ERROR) << "Failed to parse '" << value_name << "': " << error_message
59                << " (" << error_code << ").";
60     return scoped_ptr<base::DictionaryValue>();
61   }
62 
63   if (value->GetType() != base::Value::TYPE_DICTIONARY) {
64     LOG(ERROR) << "Failed to parse '" << value_name << "': not a dictionary.";
65     return scoped_ptr<base::DictionaryValue>();
66   }
67 
68   return scoped_ptr<base::DictionaryValue>(
69       static_cast<base::DictionaryValue*>(value.release()));
70 }
71 
72 // Serializes |value| into a JSON string and writes it as value |value_name|
73 // under |key|.
WriteValue(base::win::RegKey & key,const wchar_t * value_name,scoped_ptr<base::DictionaryValue> value)74 bool WriteValue(base::win::RegKey& key,
75                 const wchar_t* value_name,
76                 scoped_ptr<base::DictionaryValue> value) {
77   std::string value_json_utf8;
78   JSONStringValueSerializer serializer(&value_json_utf8);
79   if (!serializer.Serialize(*value)) {
80     LOG(ERROR) << "Failed to serialize '" << value_name << "'";
81     return false;
82   }
83 
84   // presubmit: allow wstring
85   std::wstring value_json = base::UTF8ToWide(value_json_utf8);
86   LONG result = key.WriteValue(value_name, value_json.c_str());
87   if (result != ERROR_SUCCESS) {
88     SetLastError(result);
89     PLOG(ERROR) << "Cannot write value '" << value_name << "'";
90     return false;
91   }
92 
93   return true;
94 }
95 
96 }  // namespace
97 
98 using protocol::PairingRegistry;
99 
PairingRegistryDelegateWin()100 PairingRegistryDelegateWin::PairingRegistryDelegateWin() {
101 }
102 
~PairingRegistryDelegateWin()103 PairingRegistryDelegateWin::~PairingRegistryDelegateWin() {
104 }
105 
SetRootKeys(HKEY privileged,HKEY unprivileged)106 bool PairingRegistryDelegateWin::SetRootKeys(HKEY privileged,
107                                              HKEY unprivileged) {
108   DCHECK(!privileged_.Valid());
109   DCHECK(!unprivileged_.Valid());
110   DCHECK(unprivileged);
111 
112   if (!DuplicateKeyHandle(unprivileged, &unprivileged_))
113     return false;
114 
115   if (privileged) {
116     if (!DuplicateKeyHandle(privileged, &privileged_))
117       return false;
118   }
119 
120   return true;
121 }
122 
LoadAll()123 scoped_ptr<base::ListValue> PairingRegistryDelegateWin::LoadAll() {
124   scoped_ptr<base::ListValue> pairings(new base::ListValue());
125 
126   // Enumerate and parse all values under the unprivileged key.
127   DWORD count = unprivileged_.GetValueCount();
128   for (DWORD index = 0; index < count; ++index) {
129     // presubmit: allow wstring
130     std::wstring value_name;
131     LONG result = unprivileged_.GetValueNameAt(index, &value_name);
132     if (result != ERROR_SUCCESS) {
133       SetLastError(result);
134       PLOG(ERROR) << "Cannot get the name of value " << index;
135       continue;
136     }
137 
138     PairingRegistry::Pairing pairing = Load(base::WideToUTF8(value_name));
139     if (pairing.is_valid())
140       pairings->Append(pairing.ToValue().release());
141   }
142 
143   return pairings.Pass();
144 }
145 
DeleteAll()146 bool PairingRegistryDelegateWin::DeleteAll() {
147   if (!privileged_.Valid()) {
148     LOG(ERROR) << "Cannot delete pairings: the delegate is read-only.";
149     return false;
150   }
151 
152   // Enumerate and delete the values in the privileged and unprivileged keys
153   // separately in case they get out of sync.
154   bool success = true;
155   DWORD count = unprivileged_.GetValueCount();
156   while (count > 0) {
157     // presubmit: allow wstring
158     std::wstring value_name;
159     LONG result = unprivileged_.GetValueNameAt(0, &value_name);
160     if (result == ERROR_SUCCESS)
161       result = unprivileged_.DeleteValue(value_name.c_str());
162 
163     success = success && (result == ERROR_SUCCESS);
164     count = unprivileged_.GetValueCount();
165   }
166 
167   count = privileged_.GetValueCount();
168   while (count > 0) {
169     // presubmit: allow wstring
170     std::wstring value_name;
171     LONG result = privileged_.GetValueNameAt(0, &value_name);
172     if (result == ERROR_SUCCESS)
173       result = privileged_.DeleteValue(value_name.c_str());
174 
175     success = success && (result == ERROR_SUCCESS);
176     count = privileged_.GetValueCount();
177   }
178 
179   return success;
180 }
181 
Load(const std::string & client_id)182 PairingRegistry::Pairing PairingRegistryDelegateWin::Load(
183     const std::string& client_id) {
184   // presubmit: allow wstring
185   std::wstring value_name = base::UTF8ToWide(client_id);
186 
187   // Read unprivileged fields first.
188   scoped_ptr<base::DictionaryValue> pairing = ReadValue(unprivileged_,
189                                                         value_name.c_str());
190   if (!pairing)
191     return PairingRegistry::Pairing();
192 
193   // Read the shared secret.
194   if (privileged_.Valid()) {
195     scoped_ptr<base::DictionaryValue> secret = ReadValue(privileged_,
196                                                          value_name.c_str());
197     if (!secret)
198       return PairingRegistry::Pairing();
199 
200     // Merge the two dictionaries.
201     pairing->MergeDictionary(secret.get());
202   }
203 
204   return PairingRegistry::Pairing::CreateFromValue(*pairing);
205 }
206 
Save(const PairingRegistry::Pairing & pairing)207 bool PairingRegistryDelegateWin::Save(const PairingRegistry::Pairing& pairing) {
208   if (!privileged_.Valid()) {
209     LOG(ERROR) << "Cannot save pairing entry '" << pairing.client_id()
210                 << "': the delegate is read-only.";
211     return false;
212   }
213 
214   // Convert pairing to JSON.
215   scoped_ptr<base::DictionaryValue> pairing_json = pairing.ToValue();
216 
217   // Extract the shared secret to a separate dictionary.
218   scoped_ptr<base::Value> secret_key;
219   CHECK(pairing_json->Remove(PairingRegistry::kSharedSecretKey, &secret_key));
220   scoped_ptr<base::DictionaryValue> secret_json(new base::DictionaryValue());
221   secret_json->Set(PairingRegistry::kSharedSecretKey, secret_key.release());
222 
223   // presubmit: allow wstring
224   std::wstring value_name = base::UTF8ToWide(pairing.client_id());
225 
226   // Write pairing to the registry.
227   if (!WriteValue(privileged_, value_name.c_str(), secret_json.Pass()) ||
228       !WriteValue(unprivileged_, value_name.c_str(), pairing_json.Pass())) {
229     return false;
230   }
231 
232   return true;
233 }
234 
Delete(const std::string & client_id)235 bool PairingRegistryDelegateWin::Delete(const std::string& client_id) {
236   if (!privileged_.Valid()) {
237     LOG(ERROR) << "Cannot delete pairing entry '" << client_id
238                 << "': the delegate is read-only.";
239     return false;
240   }
241 
242   // presubmit: allow wstring
243   std::wstring value_name = base::UTF8ToWide(client_id);
244   LONG result = privileged_.DeleteValue(value_name.c_str());
245   if (result != ERROR_SUCCESS &&
246       result != ERROR_FILE_NOT_FOUND &&
247       result != ERROR_PATH_NOT_FOUND) {
248     SetLastError(result);
249     PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
250     return false;
251   }
252 
253   result = unprivileged_.DeleteValue(value_name.c_str());
254   if (result != ERROR_SUCCESS &&
255       result != ERROR_FILE_NOT_FOUND &&
256       result != ERROR_PATH_NOT_FOUND) {
257     SetLastError(result);
258     PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
259     return false;
260   }
261 
262   return true;
263 }
264 
CreatePairingRegistryDelegate()265 scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() {
266   return scoped_ptr<PairingRegistry::Delegate>(
267       new PairingRegistryDelegateWin());
268 }
269 
270 }  // namespace remoting
271