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,
     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 
     99 using protocol::PairingRegistry;
    100 
    101 PairingRegistryDelegateWin::PairingRegistryDelegateWin() {
    102 }
    103 
    104 PairingRegistryDelegateWin::~PairingRegistryDelegateWin() {
    105 }
    106 
    107 bool 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 
    124 scoped_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 
    147 bool 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 
    169 PairingRegistry::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 
    194 bool 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 
    222 bool 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 
    252 scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() {
    253   return scoped_ptr<PairingRegistry::Delegate>();
    254 }
    255 
    256 }  // namespace remoting
    257