pairing_registry_delegate_win.cc 8.1 KB

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