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