Home | History | Annotate | Download | only in host
      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