Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / host / pairing_registry_delegate_win.cc
bloba714e31c38432388ce74c846f9a2d71dd45404cd
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.
5 #include "remoting/host/pairing_registry_delegate_win.h"
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"
13 namespace remoting {
15 namespace {
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.
20 bool DuplicateKeyHandle(HKEY source, base::win::RegKey* dest) {
21 HANDLE handle;
22 if (!DuplicateHandle(GetCurrentProcess(),
23 source,
24 GetCurrentProcess(),
25 &handle,
27 FALSE,
28 DUPLICATE_SAME_ACCESS)) {
29 PLOG(ERROR) << "Failed to duplicate a registry key handle";
30 return false;
33 dest->Set(reinterpret_cast<HKEY>(handle));
34 return true;
37 // Reads value |value_name| from |key| as a JSON string and returns it as
38 // |base::Value|.
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 nullptr;
50 // Parse the value.
51 std::string value_json_utf8 = base::WideToUTF8(value_json);
52 JSONStringValueDeserializer deserializer(value_json_utf8);
53 int error_code;
54 std::string error_message;
55 scoped_ptr<base::Value> value(deserializer.Deserialize(&error_code,
56 &error_message));
57 if (!value) {
58 LOG(ERROR) << "Failed to parse '" << value_name << "': " << error_message
59 << " (" << error_code << ").";
60 return nullptr;
63 if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
64 LOG(ERROR) << "Failed to parse '" << value_name << "': not a dictionary.";
65 return nullptr;
68 return make_scoped_ptr(static_cast<base::DictionaryValue*>(value.release()));
71 // Serializes |value| into a JSON string and writes it as value |value_name|
72 // under |key|.
73 bool WriteValue(base::win::RegKey& key,
74 const wchar_t* value_name,
75 scoped_ptr<base::DictionaryValue> value) {
76 std::string value_json_utf8;
77 JSONStringValueSerializer serializer(&value_json_utf8);
78 if (!serializer.Serialize(*value)) {
79 LOG(ERROR) << "Failed to serialize '" << value_name << "'";
80 return false;
83 // presubmit: allow wstring
84 std::wstring value_json = base::UTF8ToWide(value_json_utf8);
85 LONG result = key.WriteValue(value_name, value_json.c_str());
86 if (result != ERROR_SUCCESS) {
87 SetLastError(result);
88 PLOG(ERROR) << "Cannot write value '" << value_name << "'";
89 return false;
92 return true;
95 } // namespace
97 using protocol::PairingRegistry;
99 PairingRegistryDelegateWin::PairingRegistryDelegateWin() {
102 PairingRegistryDelegateWin::~PairingRegistryDelegateWin() {
105 bool PairingRegistryDelegateWin::SetRootKeys(HKEY privileged,
106 HKEY unprivileged) {
107 DCHECK(!privileged_.Valid());
108 DCHECK(!unprivileged_.Valid());
109 DCHECK(unprivileged);
111 if (!DuplicateKeyHandle(unprivileged, &unprivileged_))
112 return false;
114 if (privileged) {
115 if (!DuplicateKeyHandle(privileged, &privileged_))
116 return false;
119 return true;
122 scoped_ptr<base::ListValue> PairingRegistryDelegateWin::LoadAll() {
123 scoped_ptr<base::ListValue> pairings(new base::ListValue());
125 // Enumerate and parse all values under the unprivileged key.
126 DWORD count = unprivileged_.GetValueCount();
127 for (DWORD index = 0; index < count; ++index) {
128 // presubmit: allow wstring
129 std::wstring value_name;
130 LONG result = unprivileged_.GetValueNameAt(index, &value_name);
131 if (result != ERROR_SUCCESS) {
132 SetLastError(result);
133 PLOG(ERROR) << "Cannot get the name of value " << index;
134 continue;
137 PairingRegistry::Pairing pairing = Load(base::WideToUTF8(value_name));
138 if (pairing.is_valid())
139 pairings->Append(pairing.ToValue().release());
142 return pairings.Pass();
145 bool PairingRegistryDelegateWin::DeleteAll() {
146 if (!privileged_.Valid()) {
147 LOG(ERROR) << "Cannot delete pairings: the delegate is read-only.";
148 return false;
151 // Enumerate and delete the values in the privileged and unprivileged keys
152 // separately in case they get out of sync.
153 bool success = true;
154 DWORD count = unprivileged_.GetValueCount();
155 while (count > 0) {
156 // presubmit: allow wstring
157 std::wstring value_name;
158 LONG result = unprivileged_.GetValueNameAt(0, &value_name);
159 if (result == ERROR_SUCCESS)
160 result = unprivileged_.DeleteValue(value_name.c_str());
162 success = success && (result == ERROR_SUCCESS);
163 count = unprivileged_.GetValueCount();
166 count = privileged_.GetValueCount();
167 while (count > 0) {
168 // presubmit: allow wstring
169 std::wstring value_name;
170 LONG result = privileged_.GetValueNameAt(0, &value_name);
171 if (result == ERROR_SUCCESS)
172 result = privileged_.DeleteValue(value_name.c_str());
174 success = success && (result == ERROR_SUCCESS);
175 count = privileged_.GetValueCount();
178 return success;
181 PairingRegistry::Pairing PairingRegistryDelegateWin::Load(
182 const std::string& client_id) {
183 // presubmit: allow wstring
184 std::wstring value_name = base::UTF8ToWide(client_id);
186 // Read unprivileged fields first.
187 scoped_ptr<base::DictionaryValue> pairing = ReadValue(unprivileged_,
188 value_name.c_str());
189 if (!pairing)
190 return PairingRegistry::Pairing();
192 // Read the shared secret.
193 if (privileged_.Valid()) {
194 scoped_ptr<base::DictionaryValue> secret = ReadValue(privileged_,
195 value_name.c_str());
196 if (!secret)
197 return PairingRegistry::Pairing();
199 // Merge the two dictionaries.
200 pairing->MergeDictionary(secret.get());
203 return PairingRegistry::Pairing::CreateFromValue(*pairing);
206 bool PairingRegistryDelegateWin::Save(const PairingRegistry::Pairing& pairing) {
207 if (!privileged_.Valid()) {
208 LOG(ERROR) << "Cannot save pairing entry '" << pairing.client_id()
209 << "': the pairing registry privileged key is invalid.";
210 return false;
213 // Convert pairing to JSON.
214 scoped_ptr<base::DictionaryValue> pairing_json = pairing.ToValue();
216 // Extract the shared secret to a separate dictionary.
217 scoped_ptr<base::Value> secret_key;
218 CHECK(pairing_json->Remove(PairingRegistry::kSharedSecretKey, &secret_key));
219 scoped_ptr<base::DictionaryValue> secret_json(new base::DictionaryValue());
220 secret_json->Set(PairingRegistry::kSharedSecretKey, secret_key.release());
222 // presubmit: allow wstring
223 std::wstring value_name = base::UTF8ToWide(pairing.client_id());
225 // Write pairing to the registry.
226 if (!WriteValue(privileged_, value_name.c_str(), secret_json.Pass()) ||
227 !WriteValue(unprivileged_, value_name.c_str(), pairing_json.Pass())) {
228 return false;
231 return true;
234 bool PairingRegistryDelegateWin::Delete(const std::string& client_id) {
235 if (!privileged_.Valid()) {
236 LOG(ERROR) << "Cannot delete pairing entry '" << client_id
237 << "': the delegate is read-only.";
238 return false;
241 // presubmit: allow wstring
242 std::wstring value_name = base::UTF8ToWide(client_id);
243 LONG result = privileged_.DeleteValue(value_name.c_str());
244 if (result != ERROR_SUCCESS &&
245 result != ERROR_FILE_NOT_FOUND &&
246 result != ERROR_PATH_NOT_FOUND) {
247 SetLastError(result);
248 PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
249 return false;
252 result = unprivileged_.DeleteValue(value_name.c_str());
253 if (result != ERROR_SUCCESS &&
254 result != ERROR_FILE_NOT_FOUND &&
255 result != ERROR_PATH_NOT_FOUND) {
256 SetLastError(result);
257 PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
258 return false;
261 return true;
264 scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() {
265 return make_scoped_ptr(new PairingRegistryDelegateWin());
268 } // namespace remoting