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 13namespace remoting { 14 15namespace { 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. 20bool 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|. 39scoped_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 = 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|. 74bool 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 = UTF8ToWide(value_json_utf8); 86 LONG result = key.WriteValue(value_name, 87 UTF8ToWide(value_json_utf8).c_str()); 88 if (result != ERROR_SUCCESS) { 89 SetLastError(result); 90 PLOG(ERROR) << "Cannot write value '" << value_name << "'"; 91 return false; 92 } 93 94 return true; 95} 96 97} // namespace 98 99using protocol::PairingRegistry; 100 101PairingRegistryDelegateWin::PairingRegistryDelegateWin() { 102} 103 104PairingRegistryDelegateWin::~PairingRegistryDelegateWin() { 105} 106 107bool PairingRegistryDelegateWin::SetRootKeys(HKEY privileged, 108 HKEY unprivileged) { 109 DCHECK(!privileged_.Valid()); 110 DCHECK(!unprivileged_.Valid()); 111 DCHECK(unprivileged); 112 113 if (!DuplicateKeyHandle(unprivileged, &unprivileged_)) 114 return false; 115 116 if (privileged) { 117 if (!DuplicateKeyHandle(privileged, &privileged_)) 118 return false; 119 } 120 121 return true; 122} 123 124scoped_ptr<base::ListValue> PairingRegistryDelegateWin::LoadAll() { 125 scoped_ptr<base::ListValue> pairings(new base::ListValue()); 126 127 // Enumerate and parse all values under the unprivileged key. 128 DWORD count = unprivileged_.GetValueCount(); 129 for (DWORD index = 0; index < count; ++index) { 130 // presubmit: allow wstring 131 std::wstring value_name; 132 LONG result = unprivileged_.GetValueNameAt(index, &value_name); 133 if (result != ERROR_SUCCESS) { 134 SetLastError(result); 135 PLOG(ERROR) << "Cannot get the name of value " << index; 136 continue; 137 } 138 139 PairingRegistry::Pairing pairing = Load(WideToUTF8(value_name)); 140 if (pairing.is_valid()) 141 pairings->Append(pairing.ToValue().release()); 142 } 143 144 return pairings.Pass(); 145} 146 147bool PairingRegistryDelegateWin::DeleteAll() { 148 if (!privileged_.Valid()) { 149 LOG(ERROR) << "Cannot delete pairings: the delegate is read-only."; 150 return false; 151 } 152 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()); 161 162 success = success && (result == ERROR_SUCCESS); 163 count = unprivileged_.GetValueCount(); 164 } 165 166 return success; 167} 168 169PairingRegistry::Pairing PairingRegistryDelegateWin::Load( 170 const std::string& client_id) { 171 // presubmit: allow wstring 172 std::wstring value_name = UTF8ToWide(client_id); 173 174 // Read unprivileged fields first. 175 scoped_ptr<base::DictionaryValue> pairing = ReadValue(unprivileged_, 176 value_name.c_str()); 177 if (!pairing) 178 return PairingRegistry::Pairing(); 179 180 // Read the shared secret. 181 if (privileged_.Valid()) { 182 scoped_ptr<base::DictionaryValue> secret = ReadValue(privileged_, 183 value_name.c_str()); 184 if (!secret) 185 return PairingRegistry::Pairing(); 186 187 // Merge the two dictionaries. 188 pairing->MergeDictionary(secret.get()); 189 } 190 191 return PairingRegistry::Pairing::CreateFromValue(*pairing); 192} 193 194bool PairingRegistryDelegateWin::Save(const PairingRegistry::Pairing& pairing) { 195 if (!privileged_.Valid()) { 196 LOG(ERROR) << "Cannot save pairing entry '" << pairing.client_id() 197 << "': the delegate is read-only."; 198 return false; 199 } 200 201 // Convert pairing to JSON. 202 scoped_ptr<base::DictionaryValue> pairing_json = pairing.ToValue(); 203 204 // Extract the shared secret to a separate dictionary. 205 scoped_ptr<base::Value> secret_key; 206 CHECK(pairing_json->Remove(PairingRegistry::kSharedSecretKey, &secret_key)); 207 scoped_ptr<base::DictionaryValue> secret_json(new base::DictionaryValue()); 208 secret_json->Set(PairingRegistry::kSharedSecretKey, secret_key.release()); 209 210 // presubmit: allow wstring 211 std::wstring value_name = UTF8ToWide(pairing.client_id()); 212 213 // Write pairing to the registry. 214 if (!WriteValue(privileged_, value_name.c_str(), secret_json.Pass()) || 215 !WriteValue(unprivileged_, value_name.c_str(), pairing_json.Pass())) { 216 return false; 217 } 218 219 return true; 220} 221 222bool PairingRegistryDelegateWin::Delete(const std::string& client_id) { 223 if (!privileged_.Valid()) { 224 LOG(ERROR) << "Cannot delete pairing entry '" << client_id 225 << "': the delegate is read-only."; 226 return false; 227 } 228 229 // presubmit: allow wstring 230 std::wstring value_name = UTF8ToWide(client_id); 231 LONG result = privileged_.DeleteValue(value_name.c_str()); 232 if (result != ERROR_SUCCESS && 233 result != ERROR_FILE_NOT_FOUND && 234 result != ERROR_PATH_NOT_FOUND) { 235 SetLastError(result); 236 PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'"; 237 return false; 238 } 239 240 result = unprivileged_.DeleteValue(value_name.c_str()); 241 if (result != ERROR_SUCCESS && 242 result != ERROR_FILE_NOT_FOUND && 243 result != ERROR_PATH_NOT_FOUND) { 244 SetLastError(result); 245 PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'"; 246 return false; 247 } 248 249 return true; 250} 251 252scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() { 253 return scoped_ptr<PairingRegistry::Delegate>(); 254} 255 256} // namespace remoting 257