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