Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/json_store.h"
     18 
     19 #include <fcntl.h>
     20 #include <sys/stat.h>
     21 #include <sys/types.h>
     22 #include <unistd.h>
     23 
     24 #include <cinttypes>
     25 #include <map>
     26 #include <memory>
     27 #include <typeinfo>
     28 #include <vector>
     29 
     30 #include <base/files/important_file_writer.h>
     31 #include <base/files/file_util.h>
     32 #include <base/json/json_string_value_serializer.h>
     33 #include <base/memory/scoped_ptr.h>
     34 #include <base/strings/string_number_conversions.h>
     35 #include <base/strings/string_util.h>
     36 #include <base/strings/stringprintf.h>
     37 #include <base/values.h>
     38 
     39 #include "shill/crypto_rot47.h"
     40 #include "shill/logging.h"
     41 #include "shill/scoped_umask.h"
     42 
     43 using std::map;
     44 using std::set;
     45 using std::string;
     46 using std::unique_ptr;
     47 using std::vector;
     48 
     49 namespace shill {
     50 
     51 namespace Logging {
     52 
     53 static auto kModuleLogScope = ScopeLogger::kStorage;
     54 static string ObjectID(const JsonStore* j) {
     55   return "(unknown)";
     56 }
     57 
     58 }  // namespace Logging
     59 
     60 namespace {
     61 
     62 static const char kCorruptSuffix[] = ".corrupted";
     63 static const char kCoercedValuePropertyEncodedValue[] = "_encoded_value";
     64 static const char kCoercedValuePropertyNativeType[] = "_native_type";
     65 static const char kNativeTypeNonAsciiString[] = "non_ascii_string";
     66 static const char kNativeTypeUint64[] = "uint64";
     67 static const char kRootPropertyDescription[] = "description";
     68 static const char kRootPropertySettings[] = "settings";
     69 
     70 bool DoesGroupContainProperties(
     71     const brillo::VariantDictionary& group,
     72     const brillo::VariantDictionary& required_properties) {
     73   for (const auto& required_property_name_and_value : required_properties) {
     74     const auto& required_key = required_property_name_and_value.first;
     75     const auto& required_value = required_property_name_and_value.second;
     76     const auto& group_it = group.find(required_key);
     77     if (group_it == group.end() || group_it->second != required_value) {
     78       return false;
     79     }
     80   }
     81   return true;
     82 }
     83 
     84 // Deserialization helpers.
     85 
     86 // A coerced value is used to represent values that base::Value does
     87 // not directly support.  A coerced value has the form
     88 //   {'_native_type': <type-as-string>, '_encoded_value': <value-as-string>}
     89 bool IsCoercedValue(const base::DictionaryValue& value) {
     90   return value.HasKey(kCoercedValuePropertyNativeType) &&
     91       value.HasKey(kCoercedValuePropertyEncodedValue);
     92 }
     93 
     94 unique_ptr<brillo::Any> DecodeCoercedValue(
     95     const base::DictionaryValue& coerced_value) {
     96   string native_type;
     97   if (!coerced_value.GetStringWithoutPathExpansion(
     98           kCoercedValuePropertyNativeType, &native_type)) {
     99     LOG(ERROR) << "Property |" << kCoercedValuePropertyNativeType
    100                << "| is not a string.";
    101     return nullptr;
    102   }
    103 
    104   string encoded_value;
    105   if (!coerced_value.GetStringWithoutPathExpansion(
    106           kCoercedValuePropertyEncodedValue, &encoded_value)) {
    107     LOG(ERROR) << "Property |" << kCoercedValuePropertyEncodedValue
    108                << "| is not a string.";
    109     return nullptr;
    110   }
    111 
    112   if (native_type == kNativeTypeNonAsciiString) {
    113     vector<uint8_t> native_value;
    114     if (base::HexStringToBytes(encoded_value, &native_value)) {
    115       return unique_ptr<brillo::Any>(
    116           new brillo::Any(string(native_value.begin(), native_value.end())));
    117     } else {
    118       LOG(ERROR) << "Failed to decode hex data from |" << encoded_value << "|.";
    119       return nullptr;
    120     }
    121   } else if (native_type == kNativeTypeUint64) {
    122     uint64_t native_value;
    123     if (base::StringToUint64(encoded_value, &native_value)) {
    124       return unique_ptr<brillo::Any>(new brillo::Any(native_value));
    125     } else {
    126       LOG(ERROR) << "Failed to parse uint64 from |" << encoded_value << "|.";
    127       return nullptr;
    128     }
    129   } else {
    130     LOG(ERROR) << "Unsupported native type |" << native_type << "|.";
    131     return nullptr;
    132   }
    133 }
    134 
    135 unique_ptr<string> MakeStringFromValue(const base::Value& value) {
    136   const auto value_type = value.GetType();
    137 
    138   if (value_type == base::Value::TYPE_STRING) {
    139     unique_ptr<string> unwrapped_string(new string());
    140     value.GetAsString(unwrapped_string.get());
    141     return unwrapped_string;
    142   } else if (value_type == base::Value::TYPE_DICTIONARY) {
    143     const base::DictionaryValue* dictionary_value;
    144     value.GetAsDictionary(&dictionary_value);
    145     unique_ptr<brillo::Any> decoded_value(
    146         DecodeCoercedValue(*dictionary_value));
    147     if (!decoded_value) {
    148       LOG(ERROR) << "Failed to decode coerced value.";
    149       return nullptr;
    150     }
    151 
    152     if (!decoded_value->IsTypeCompatible<string>()) {
    153       LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<string>()
    154                  << "| from |" << decoded_value->GetUndecoratedTypeName()
    155                  << ".";
    156       return nullptr;
    157     }
    158     return unique_ptr<string>(new string(decoded_value->Get<string>()));
    159   } else {
    160     LOG(ERROR) << "Got unexpected type |" << value_type << "|.";
    161     return nullptr;
    162   }
    163 }
    164 
    165 unique_ptr<vector<string>> ConvertListValueToStringVector(
    166     const base::ListValue& list_value) {
    167   const size_t list_len = list_value.GetSize();
    168   for (size_t i = 0; i < list_len; ++i) {
    169     const base::Value* list_item;
    170     list_value.Get(i, &list_item);
    171     const auto item_type = list_item->GetType();
    172     if (item_type != base::Value::TYPE_STRING &&
    173         item_type != base::Value::TYPE_DICTIONARY) {
    174       LOG(ERROR) << "Element " << i << " has type " << item_type << ", "
    175                  << "instead of expected types "
    176                  << base::Value::TYPE_STRING << "  or "
    177                  << base::Value::TYPE_DICTIONARY << ".";
    178       return nullptr;
    179     }
    180   }
    181 
    182   unique_ptr<vector<string>> result(new vector<string>);
    183   for (size_t i = 0; i < list_len; ++i) {
    184     const base::Value* list_item;
    185     unique_ptr<string> native_string;
    186     list_value.Get(i, &list_item);
    187     native_string = MakeStringFromValue(*list_item);
    188     if (!native_string) {
    189       LOG(ERROR) << "Failed to parse string from element " << i << ".";
    190       return nullptr;
    191     }
    192     result->push_back(*native_string);
    193   }
    194   return result;
    195 }
    196 
    197 unique_ptr<brillo::VariantDictionary>
    198 ConvertDictionaryValueToVariantDictionary(
    199     const base::DictionaryValue& dictionary_value) {
    200   base::DictionaryValue::Iterator it(dictionary_value);
    201   unique_ptr<brillo::VariantDictionary> variant_dictionary(
    202       new brillo::VariantDictionary());
    203   while (!it.IsAtEnd()) {
    204     const string& key = it.key();
    205     const base::Value& value = it.value();
    206     switch (value.GetType()) {
    207       case base::Value::TYPE_NULL:
    208         LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_NULL.";
    209         return nullptr;
    210       case base::Value::TYPE_BOOLEAN: {
    211         bool native_bool;
    212         value.GetAsBoolean(&native_bool);
    213         (*variant_dictionary)[key] = native_bool;
    214         break;
    215       }
    216       case base::Value::TYPE_INTEGER: {
    217         int native_int;
    218         value.GetAsInteger(&native_int);
    219         (*variant_dictionary)[key] = native_int;
    220         break;
    221       }
    222       case base::Value::TYPE_DOUBLE:
    223         LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_DOUBLE.";
    224         return nullptr;
    225       case base::Value::TYPE_STRING: {
    226         string native_string;
    227         value.GetAsString(&native_string);
    228         (*variant_dictionary)[key] = native_string;
    229         break;
    230       }
    231       case base::Value::TYPE_BINARY:
    232         /* The JSON parser should never create Values of this type. */
    233         LOG(ERROR) << "Key |" << key << "| has unexpected TYPE_BINARY.";
    234         return nullptr;
    235       case base::Value::TYPE_DICTIONARY: {
    236         const base::DictionaryValue* dictionary_value;
    237         value.GetAsDictionary(&dictionary_value);
    238         if (!IsCoercedValue(*dictionary_value)) {
    239           LOG(ERROR) << "Key |" << key << "| has unsupported TYPE_DICTIONARY.";
    240           return nullptr;
    241         }
    242         unique_ptr<brillo::Any> decoded_coerced_value(
    243             DecodeCoercedValue(*dictionary_value));
    244         if (!decoded_coerced_value) {
    245           LOG(ERROR) << "Key |" << key << "| could not be decoded.";
    246           return nullptr;
    247         }
    248         (*variant_dictionary)[key] = *decoded_coerced_value;
    249         break;
    250       }
    251       case base::Value::TYPE_LIST: {  // Only string lists, for now.
    252         const base::ListValue* list_value;
    253         value.GetAsList(&list_value);
    254 
    255         unique_ptr<vector<string>> string_list(
    256             ConvertListValueToStringVector(*list_value));
    257         if (!string_list) {
    258           LOG(ERROR) << "Key |" << key << "| could not be decoded.";
    259           return nullptr;
    260         }
    261         (*variant_dictionary)[key] = *string_list;
    262         break;
    263       }
    264     }
    265     it.Advance();
    266   }
    267   return variant_dictionary;
    268 }
    269 
    270 // Serialization helpers.
    271 
    272 scoped_ptr<base::DictionaryValue> MakeCoercedValue(
    273     const string& native_type, const string& encoded_value) {
    274   auto coerced_value(make_scoped_ptr(new base::DictionaryValue()));
    275   coerced_value->SetStringWithoutPathExpansion(
    276       kCoercedValuePropertyNativeType, native_type);
    277   coerced_value->SetStringWithoutPathExpansion(
    278       kCoercedValuePropertyEncodedValue, encoded_value);
    279   return coerced_value;
    280 }
    281 
    282 scoped_ptr<base::Value> MakeValueForString(const string& native_string) {
    283   // Strictly speaking, we don't need to escape non-ASCII text, if
    284   // that text is UTF-8.  Practically speaking, however, it'll be
    285   // easier to inspect config files if all non-ASCII strings are
    286   // presented as byte sequences. (Unicode has many code points with
    287   // similar-looking glyphs.)
    288   if (base::IsStringASCII(native_string) &&
    289       native_string.find('\0') == string::npos) {
    290     return make_scoped_ptr(new base::StringValue(native_string));
    291   } else {
    292     const string hex_encoded_string(
    293         base::HexEncode(native_string.data(), native_string.size()));
    294     return MakeCoercedValue(kNativeTypeNonAsciiString, hex_encoded_string);
    295   }
    296 }
    297 
    298 scoped_ptr<base::DictionaryValue> ConvertVariantDictionaryToDictionaryValue(
    299     const brillo::VariantDictionary& variant_dictionary) {
    300   auto dictionary_value(make_scoped_ptr(new base::DictionaryValue()));
    301   for (const auto& key_and_value : variant_dictionary) {
    302     const auto& key = key_and_value.first;
    303     const auto& value = key_and_value.second;
    304     if (value.IsTypeCompatible<bool>()) {
    305       dictionary_value->SetBooleanWithoutPathExpansion(key, value.Get<bool>());
    306     } else if (value.IsTypeCompatible<int32_t>()) {
    307       dictionary_value->SetIntegerWithoutPathExpansion(key, value.Get<int>());
    308     } else if (value.IsTypeCompatible<string>()) {
    309       dictionary_value->SetWithoutPathExpansion(
    310           key, MakeValueForString(value.Get<string>()));
    311     } else if (value.IsTypeCompatible<uint64_t>()) {
    312       const string encoded_value(
    313           base::StringPrintf("%" PRIu64, value.Get<uint64_t>()));
    314       dictionary_value->SetWithoutPathExpansion(
    315           key, MakeCoercedValue(kNativeTypeUint64, encoded_value));
    316     } else if (value.IsTypeCompatible<vector<string>>()) {
    317       auto list_value(make_scoped_ptr(new base::ListValue()));
    318       for (const auto& string_list_item : value.Get<vector<string>>()) {
    319         list_value->Append(MakeValueForString(string_list_item));
    320       }
    321       dictionary_value->SetWithoutPathExpansion(key, std::move(list_value));
    322     } else {
    323       LOG(ERROR) << "Failed to convert element with key |" << key << "|.";
    324       return nullptr;
    325     }
    326   }
    327   return dictionary_value;
    328 }
    329 
    330 }  // namespace
    331 
    332 JsonStore::JsonStore(const base::FilePath& path)
    333     : path_(path) {
    334   CHECK(!path_.empty());
    335 }
    336 
    337 bool JsonStore::IsNonEmpty() const {
    338   int64_t file_size = 0;
    339   return base::GetFileSize(path_, &file_size) && file_size != 0;
    340 }
    341 
    342 bool JsonStore::Open() {
    343   if (!IsNonEmpty()) {
    344     LOG(INFO) << "Creating a new key file at |" << path_.value() << "|.";
    345     return true;
    346   }
    347 
    348   string json_string;
    349   if (!base::ReadFileToString(path_, &json_string)) {
    350     LOG(ERROR) << "Failed to read data from |" << path_.value() << "|.";
    351     return false;
    352   }
    353 
    354   JSONStringValueDeserializer json_deserializer(json_string);
    355   unique_ptr<base::Value> json_value;
    356   string json_error;
    357   json_deserializer.set_allow_trailing_comma(true);
    358   json_value.reset(
    359       json_deserializer.Deserialize(nullptr, &json_error).release());
    360   if (!json_value) {
    361     LOG(ERROR) << "Failed to parse JSON data from |" << path_.value() <<"|.";
    362     SLOG(this, 5) << json_error;
    363     return false;
    364   }
    365 
    366   const base::DictionaryValue* root_dictionary;
    367   if (!json_value->GetAsDictionary(&root_dictionary)) {
    368     LOG(ERROR) << "JSON value is not a dictionary.";
    369     return false;
    370   }
    371 
    372   CHECK(root_dictionary);
    373   if (root_dictionary->HasKey(kRootPropertyDescription) &&
    374       !root_dictionary->GetStringWithoutPathExpansion(
    375           kRootPropertyDescription, &file_description_)) {
    376     LOG(WARNING) << "Property |" << kRootPropertyDescription
    377                  << "| is not a string.";
    378     // Description is non-critical, so continue processing.
    379   }
    380 
    381   if (!root_dictionary->HasKey(kRootPropertySettings)) {
    382     LOG(ERROR) << "Property |" << kRootPropertySettings << "| is missing.";
    383     return false;
    384   }
    385 
    386   const base::DictionaryValue* settings_dictionary;
    387   if (!root_dictionary->GetDictionaryWithoutPathExpansion(
    388           kRootPropertySettings, &settings_dictionary)) {
    389     LOG(ERROR) << "Property |" << kRootPropertySettings
    390                << "| is not a dictionary.";
    391     return false;
    392   }
    393 
    394   if (!group_name_to_settings_.empty()) {
    395     LOG(INFO) << "Clearing existing settings on open.";
    396     group_name_to_settings_.clear();
    397   }
    398 
    399   base::DictionaryValue::Iterator it(*settings_dictionary);
    400   while (!it.IsAtEnd()) {
    401     const string& group_name = it.key();
    402     const base::DictionaryValue* group_settings_as_values;
    403     if (!it.value().GetAsDictionary(&group_settings_as_values)) {
    404       LOG(ERROR) << "Group |" << group_name << "| is not a dictionary.";
    405       return false;
    406     }
    407 
    408     unique_ptr<brillo::VariantDictionary> group_settings_as_variants =
    409         ConvertDictionaryValueToVariantDictionary(*group_settings_as_values);
    410     if (!group_settings_as_variants) {
    411       LOG(ERROR) << "Failed to convert group |" << group_name
    412                  << "| to variants.";
    413       return false;
    414     }
    415 
    416     group_name_to_settings_[group_name] = *group_settings_as_variants;
    417     it.Advance();
    418   }
    419 
    420   return true;
    421 }
    422 
    423 bool JsonStore::Close() {
    424   return Flush();
    425 }
    426 
    427 bool JsonStore::Flush() {
    428   auto groups(make_scoped_ptr(new base::DictionaryValue()));
    429   for (const auto& group_name_and_settings : group_name_to_settings_) {
    430     const auto& group_name = group_name_and_settings.first;
    431     scoped_ptr<base::DictionaryValue> group_settings(
    432         ConvertVariantDictionaryToDictionaryValue(
    433             group_name_and_settings.second));
    434     if (!group_settings) {
    435       // This class maintains the invariant that anything placed in
    436       // |group_settings| is convertible. So abort if conversion fails.
    437       LOG(FATAL) << "Failed to convert group |" << group_name << "|.";
    438       return false;
    439     }
    440     groups->SetWithoutPathExpansion(group_name, std::move(group_settings));
    441   }
    442 
    443   base::DictionaryValue root;
    444   root.SetStringWithoutPathExpansion(
    445       kRootPropertyDescription, file_description_);
    446   root.SetWithoutPathExpansion(kRootPropertySettings, std::move(groups));
    447 
    448   string json_string;
    449   JSONStringValueSerializer json_serializer(&json_string);
    450   json_serializer.set_pretty_print(true);
    451   if (!json_serializer.Serialize(root)) {
    452     LOG(ERROR) << "Failed to serialize to JSON.";
    453     return false;
    454   }
    455 
    456   ScopedUmask owner_only_umask(~(S_IRUSR | S_IWUSR) & 0777);
    457   if (!base::ImportantFileWriter::WriteFileAtomically(path_, json_string)) {
    458     LOG(ERROR) << "Failed to write JSON file: |" << path_.value() << "|.";
    459     return false;
    460   }
    461 
    462   return true;
    463 }
    464 
    465 bool JsonStore::MarkAsCorrupted() {
    466   LOG(INFO) << "In " << __func__ << " for " << path_.value();
    467   string corrupted_path = path_.value() + kCorruptSuffix;
    468   int ret = rename(path_.value().c_str(), corrupted_path.c_str());
    469   if (ret != 0) {
    470     PLOG(ERROR) << "File rename failed.";
    471     return false;
    472   }
    473   return true;
    474 }
    475 
    476 set<string> JsonStore::GetGroups() const {
    477   set<string> matching_groups;
    478   for (const auto& group_name_and_settings : group_name_to_settings_) {
    479     matching_groups.insert(group_name_and_settings.first);
    480   }
    481   return matching_groups;
    482 }
    483 
    484 // Returns a set so that caller can easily test whether a particular group
    485 // is contained within this collection.
    486 set<string> JsonStore::GetGroupsWithKey(const string& key) const {
    487   set<string> matching_groups;
    488   // iterate over groups, find ones with matching key
    489   for (const auto& group_name_and_settings : group_name_to_settings_) {
    490     const auto& group_name = group_name_and_settings.first;
    491     const auto& group_settings = group_name_and_settings.second;
    492     if (group_settings.find(key) != group_settings.end()) {
    493       matching_groups.insert(group_name);
    494     }
    495   }
    496   return matching_groups;
    497 }
    498 
    499 set<string> JsonStore::GetGroupsWithProperties(const KeyValueStore& properties)
    500     const {
    501   set<string> matching_groups;
    502   const brillo::VariantDictionary& properties_dict(properties.properties());
    503   for (const auto& group_name_and_settings : group_name_to_settings_) {
    504     const auto& group_name = group_name_and_settings.first;
    505     const auto& group_settings = group_name_and_settings.second;
    506     if (DoesGroupContainProperties(group_settings, properties_dict)) {
    507       matching_groups.insert(group_name);
    508     }
    509   }
    510   return matching_groups;
    511 }
    512 
    513 bool JsonStore::ContainsGroup(const string& group) const {
    514   const auto& it = group_name_to_settings_.find(group);
    515   return it != group_name_to_settings_.end();
    516 }
    517 
    518 bool JsonStore::DeleteKey(const string& group, const string& key) {
    519   const auto& group_name_and_settings = group_name_to_settings_.find(group);
    520   if (group_name_and_settings == group_name_to_settings_.end()) {
    521     LOG(ERROR) << "Could not find group |" << group << "|.";
    522     return false;
    523   }
    524 
    525   auto& group_settings = group_name_and_settings->second;
    526   auto property_it = group_settings.find(key);
    527   if (property_it != group_settings.end()) {
    528     group_settings.erase(property_it);
    529   }
    530 
    531   return true;
    532 }
    533 
    534 bool JsonStore::DeleteGroup(const string& group) {
    535   auto group_name_and_settings = group_name_to_settings_.find(group);
    536   if (group_name_and_settings != group_name_to_settings_.end()) {
    537     group_name_to_settings_.erase(group_name_and_settings);
    538   }
    539   return true;
    540 }
    541 
    542 bool JsonStore::SetHeader(const string& header) {
    543   file_description_ = header;
    544   return true;
    545 }
    546 
    547 bool JsonStore::GetString(const string& group,
    548                           const string& key,
    549                           string* value) const {
    550   return ReadSetting(group, key, value);
    551 }
    552 
    553 bool JsonStore::SetString(
    554     const string& group, const string& key, const string& value) {
    555   return WriteSetting(group, key, value);
    556 }
    557 
    558 bool JsonStore::GetBool(const string& group, const string& key, bool* value)
    559     const {
    560   return ReadSetting(group, key, value);
    561 }
    562 
    563 bool JsonStore::SetBool(const string& group, const string& key, bool value) {
    564   return WriteSetting(group, key, value);
    565 }
    566 
    567 bool JsonStore::GetInt(
    568     const string& group, const string& key, int* value) const {
    569   return ReadSetting(group, key, value);
    570 }
    571 
    572 bool JsonStore::SetInt(const string& group, const string& key, int value) {
    573   return WriteSetting(group, key, value);
    574 }
    575 
    576 bool JsonStore::GetUint64(
    577     const string& group, const string& key, uint64_t* value) const {
    578   return ReadSetting(group, key, value);
    579 }
    580 
    581 bool JsonStore::SetUint64(
    582     const string& group, const string& key, uint64_t value) {
    583   return WriteSetting(group, key, value);
    584 }
    585 
    586 bool JsonStore::GetStringList(
    587     const string& group, const string& key, vector<string>* value) const {
    588   return ReadSetting(group, key, value);
    589 }
    590 
    591 bool JsonStore::SetStringList(
    592     const string& group, const string& key, const vector<string>& value) {
    593   return WriteSetting(group, key, value);
    594 }
    595 
    596 bool JsonStore::GetCryptedString(
    597     const string& group, const string& key, string* value) {
    598   string encrypted_value;
    599   if (!GetString(group, key, &encrypted_value)) {
    600     return false;
    601   }
    602 
    603   // TODO(quiche): Once we've removed the glib dependency in
    604   // CryptoProvider, move to using CryptoProvider, instead of
    605   // CryptoROT47 directly. This change should be done before using
    606   // JsonStore in production, as the on-disk format of crypted strings
    607   // will change.
    608   CryptoROT47 rot47;
    609   string decrypted_value;
    610   if (!rot47.Decrypt(encrypted_value, &decrypted_value)) {
    611     LOG(ERROR) << "Failed to decrypt value for |" << group << "|"
    612                << ":|" << key << "|.";
    613     return false;
    614   }
    615 
    616   if (value) {
    617     *value = decrypted_value;
    618   }
    619   return true;
    620 }
    621 
    622 bool JsonStore::SetCryptedString(
    623     const string& group, const string& key, const string& value) {
    624   CryptoROT47 rot47;
    625   string encrypted_value;
    626   if (!rot47.Encrypt(value, &encrypted_value)) {
    627     LOG(ERROR) << "Failed to encrypt value for |" << group << "|"
    628                << ":|" << key << "|.";
    629     return false;
    630   }
    631 
    632   return SetString(group, key, encrypted_value);
    633 }
    634 
    635 // Private methods.
    636 template<typename T>
    637 bool JsonStore::ReadSetting(
    638     const string& group, const string& key, T* out) const {
    639   const auto& group_name_and_settings = group_name_to_settings_.find(group);
    640   if (group_name_and_settings == group_name_to_settings_.end()) {
    641     SLOG(this, 10) << "Could not find group |" << group << "|.";
    642     return false;
    643   }
    644 
    645   const auto& group_settings = group_name_and_settings->second;
    646   const auto& property_name_and_value = group_settings.find(key);
    647   if (property_name_and_value == group_settings.end()) {
    648     SLOG(this, 10) << "Could not find property |" << key << "|.";
    649     return false;
    650   }
    651 
    652   if (!property_name_and_value->second.IsTypeCompatible<T>()) {
    653     // We assume that the reader and the writer agree on the exact
    654     // type. So we do not allow implicit conversion.
    655     LOG(ERROR) << "Can not read |" << brillo::GetUndecoratedTypeName<T>()
    656                << "| from |"
    657                << property_name_and_value->second.GetUndecoratedTypeName()
    658                << "|.";
    659     return false;
    660   }
    661 
    662   if (out) {
    663     return property_name_and_value->second.GetValue(out);
    664   } else {
    665     return true;
    666   }
    667 }
    668 
    669 template<typename T>
    670 bool JsonStore::WriteSetting(
    671     const string& group, const string& key, const T& new_value) {
    672   auto group_name_and_settings = group_name_to_settings_.find(group);
    673   if (group_name_and_settings == group_name_to_settings_.end()) {
    674     group_name_to_settings_[group][key] = new_value;
    675     return true;
    676   }
    677 
    678   auto& group_settings = group_name_and_settings->second;
    679   auto property_name_and_value = group_settings.find(key);
    680   if (property_name_and_value == group_settings.end()) {
    681     group_settings[key] = new_value;
    682     return true;
    683   }
    684 
    685   if (!property_name_and_value->second.IsTypeCompatible<T>()) {
    686     SLOG(this, 10) << "New type |" << brillo::GetUndecoratedTypeName<T>()
    687                    << "| differs from current type |"
    688                    << property_name_and_value->second.GetUndecoratedTypeName()
    689                    << "|.";
    690     return false;
    691   } else {
    692     property_name_and_value->second = new_value;
    693     return true;
    694   }
    695 }
    696 
    697 }  // namespace shill
    698