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"
17 // Duplicates a registry key handle (returned by RegCreateXxx/RegOpenXxx).
18 // The returned handle cannot be inherited and has the same permissions as
20 bool DuplicateKeyHandle(HKEY source
, base::win::RegKey
* dest
) {
22 if (!DuplicateHandle(GetCurrentProcess(),
28 DUPLICATE_SAME_ACCESS
)) {
29 PLOG(ERROR
) << "Failed to duplicate a registry key handle";
33 dest
->Set(reinterpret_cast<HKEY
>(handle
));
37 // Reads value |value_name| from |key| as a JSON string and returns it as
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
) {
46 PLOG(ERROR
) << "Cannot read value '" << value_name
<< "'";
47 return scoped_ptr
<base::DictionaryValue
>();
51 std::string value_json_utf8
= base::WideToUTF8(value_json
);
52 JSONStringValueSerializer
serializer(&value_json_utf8
);
54 std::string error_message
;
55 scoped_ptr
<base::Value
> value(serializer
.Deserialize(&error_code
,
58 LOG(ERROR
) << "Failed to parse '" << value_name
<< "': " << error_message
59 << " (" << error_code
<< ").";
60 return scoped_ptr
<base::DictionaryValue
>();
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
>();
68 return scoped_ptr
<base::DictionaryValue
>(
69 static_cast<base::DictionaryValue
*>(value
.release()));
72 // Serializes |value| into a JSON string and writes it as value |value_name|
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
<< "'";
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
) {
89 PLOG(ERROR
) << "Cannot write value '" << value_name
<< "'";
98 using protocol::PairingRegistry
;
100 PairingRegistryDelegateWin::PairingRegistryDelegateWin() {
103 PairingRegistryDelegateWin::~PairingRegistryDelegateWin() {
106 bool PairingRegistryDelegateWin::SetRootKeys(HKEY privileged
,
108 DCHECK(!privileged_
.Valid());
109 DCHECK(!unprivileged_
.Valid());
110 DCHECK(unprivileged
);
112 if (!DuplicateKeyHandle(unprivileged
, &unprivileged_
))
116 if (!DuplicateKeyHandle(privileged
, &privileged_
))
123 scoped_ptr
<base::ListValue
> PairingRegistryDelegateWin::LoadAll() {
124 scoped_ptr
<base::ListValue
> pairings(new base::ListValue());
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
;
138 PairingRegistry::Pairing pairing
= Load(base::WideToUTF8(value_name
));
139 if (pairing
.is_valid())
140 pairings
->Append(pairing
.ToValue().release());
143 return pairings
.Pass();
146 bool PairingRegistryDelegateWin::DeleteAll() {
147 if (!privileged_
.Valid()) {
148 LOG(ERROR
) << "Cannot delete pairings: the delegate is read-only.";
152 // Enumerate and delete the values in the privileged and unprivileged keys
153 // separately in case they get out of sync.
155 DWORD count
= unprivileged_
.GetValueCount();
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());
163 success
= success
&& (result
== ERROR_SUCCESS
);
164 count
= unprivileged_
.GetValueCount();
167 count
= privileged_
.GetValueCount();
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());
175 success
= success
&& (result
== ERROR_SUCCESS
);
176 count
= privileged_
.GetValueCount();
182 PairingRegistry::Pairing
PairingRegistryDelegateWin::Load(
183 const std::string
& client_id
) {
184 // presubmit: allow wstring
185 std::wstring value_name
= base::UTF8ToWide(client_id
);
187 // Read unprivileged fields first.
188 scoped_ptr
<base::DictionaryValue
> pairing
= ReadValue(unprivileged_
,
191 return PairingRegistry::Pairing();
193 // Read the shared secret.
194 if (privileged_
.Valid()) {
195 scoped_ptr
<base::DictionaryValue
> secret
= ReadValue(privileged_
,
198 return PairingRegistry::Pairing();
200 // Merge the two dictionaries.
201 pairing
->MergeDictionary(secret
.get());
204 return PairingRegistry::Pairing::CreateFromValue(*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.";
214 // Convert pairing to JSON.
215 scoped_ptr
<base::DictionaryValue
> pairing_json
= pairing
.ToValue();
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());
223 // presubmit: allow wstring
224 std::wstring value_name
= base::UTF8ToWide(pairing
.client_id());
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())) {
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.";
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
<< "'";
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
<< "'";
265 scoped_ptr
<PairingRegistry::Delegate
> CreatePairingRegistryDelegate() {
266 return scoped_ptr
<PairingRegistry::Delegate
>(
267 new PairingRegistryDelegateWin());
270 } // namespace remoting