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 = base::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 = base::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(base::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   // Enumerate and delete the values in the privileged and unprivileged keys
    153   // separately in case they get out of sync.
    154   bool success = true;
    155   DWORD count = unprivileged_.GetValueCount();
    156   while (count > 0) {
    157     // presubmit: allow wstring
    158     std::wstring value_name;
    159     LONG result = unprivileged_.GetValueNameAt(0, &value_name);
    160     if (result == ERROR_SUCCESS)
    161       result = unprivileged_.DeleteValue(value_name.c_str());
    162 
    163     success = success && (result == ERROR_SUCCESS);
    164     count = unprivileged_.GetValueCount();
    165   }
    166 
    167   count = privileged_.GetValueCount();
    168   while (count > 0) {
    169     // presubmit: allow wstring
    170     std::wstring value_name;
    171     LONG result = privileged_.GetValueNameAt(0, &value_name);
    172     if (result == ERROR_SUCCESS)
    173       result = privileged_.DeleteValue(value_name.c_str());
    174 
    175     success = success && (result == ERROR_SUCCESS);
    176     count = privileged_.GetValueCount();
    177   }
    178 
    179   return success;
    180 }
    181 
    182 PairingRegistry::Pairing PairingRegistryDelegateWin::Load(
    183     const std::string& client_id) {
    184   // presubmit: allow wstring
    185   std::wstring value_name = base::UTF8ToWide(client_id);
    186 
    187   // Read unprivileged fields first.
    188   scoped_ptr<base::DictionaryValue> pairing = ReadValue(unprivileged_,
    189                                                         value_name.c_str());
    190   if (!pairing)
    191     return PairingRegistry::Pairing();
    192 
    193   // Read the shared secret.
    194   if (privileged_.Valid()) {
    195     scoped_ptr<base::DictionaryValue> secret = ReadValue(privileged_,
    196                                                          value_name.c_str());
    197     if (!secret)
    198       return PairingRegistry::Pairing();
    199 
    200     // Merge the two dictionaries.
    201     pairing->MergeDictionary(secret.get());
    202   }
    203 
    204   return PairingRegistry::Pairing::CreateFromValue(*pairing);
    205 }
    206 
    207 bool PairingRegistryDelegateWin::Save(const PairingRegistry::Pairing& pairing) {
    208   if (!privileged_.Valid()) {
    209     LOG(ERROR) << "Cannot save pairing entry '" << pairing.client_id()
    210                 << "': the delegate is read-only.";
    211     return false;
    212   }
    213 
    214   // Convert pairing to JSON.
    215   scoped_ptr<base::DictionaryValue> pairing_json = pairing.ToValue();
    216 
    217   // Extract the shared secret to a separate dictionary.
    218   scoped_ptr<base::Value> secret_key;
    219   CHECK(pairing_json->Remove(PairingRegistry::kSharedSecretKey, &secret_key));
    220   scoped_ptr<base::DictionaryValue> secret_json(new base::DictionaryValue());
    221   secret_json->Set(PairingRegistry::kSharedSecretKey, secret_key.release());
    222 
    223   // presubmit: allow wstring
    224   std::wstring value_name = base::UTF8ToWide(pairing.client_id());
    225 
    226   // Write pairing to the registry.
    227   if (!WriteValue(privileged_, value_name.c_str(), secret_json.Pass()) ||
    228       !WriteValue(unprivileged_, value_name.c_str(), pairing_json.Pass())) {
    229     return false;
    230   }
    231 
    232   return true;
    233 }
    234 
    235 bool PairingRegistryDelegateWin::Delete(const std::string& client_id) {
    236   if (!privileged_.Valid()) {
    237     LOG(ERROR) << "Cannot delete pairing entry '" << client_id
    238                 << "': the delegate is read-only.";
    239     return false;
    240   }
    241 
    242   // presubmit: allow wstring
    243   std::wstring value_name = base::UTF8ToWide(client_id);
    244   LONG result = privileged_.DeleteValue(value_name.c_str());
    245   if (result != ERROR_SUCCESS &&
    246       result != ERROR_FILE_NOT_FOUND &&
    247       result != ERROR_PATH_NOT_FOUND) {
    248     SetLastError(result);
    249     PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
    250     return false;
    251   }
    252 
    253   result = unprivileged_.DeleteValue(value_name.c_str());
    254   if (result != ERROR_SUCCESS &&
    255       result != ERROR_FILE_NOT_FOUND &&
    256       result != ERROR_PATH_NOT_FOUND) {
    257     SetLastError(result);
    258     PLOG(ERROR) << "Cannot delete pairing entry '" << client_id << "'";
    259     return false;
    260   }
    261 
    262   return true;
    263 }
    264 
    265 scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() {
    266   return scoped_ptr<PairingRegistry::Delegate>(
    267       new PairingRegistryDelegateWin());
    268 }
    269 
    270 }  // namespace remoting
    271