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 "components/policy/core/common/registry_dict_win.h" 6 7 #include "base/json/json_reader.h" 8 #include "base/stl_util.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/sys_byteorder.h" 13 #include "base/values.h" 14 #include "base/win/registry.h" 15 #include "components/policy/core/common/schema.h" 16 17 using base::win::RegistryKeyIterator; 18 using base::win::RegistryValueIterator; 19 20 namespace policy { 21 22 namespace { 23 24 // Converts a value (as read from the registry) to meet |schema|, converting 25 // types as necessary. Unconvertible types will show up as NULL values in the 26 // result. 27 scoped_ptr<base::Value> ConvertValue(const base::Value& value, 28 const Schema& schema) { 29 if (!schema.valid()) 30 return make_scoped_ptr(value.DeepCopy()).Pass(); 31 32 // If the type is good already, go with it. 33 if (value.IsType(schema.type())) { 34 // Recurse for complex types. 35 const base::DictionaryValue* dict = NULL; 36 const base::ListValue* list = NULL; 37 if (value.GetAsDictionary(&dict)) { 38 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 39 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); 40 entry.Advance()) { 41 scoped_ptr<base::Value> converted = 42 ConvertValue(entry.value(), schema.GetProperty(entry.key())); 43 if (converted) 44 result->SetWithoutPathExpansion(entry.key(), converted.release()); 45 } 46 return result.PassAs<base::Value>(); 47 } else if (value.GetAsList(&list)) { 48 scoped_ptr<base::ListValue> result(new base::ListValue()); 49 for (base::ListValue::const_iterator entry(list->begin()); 50 entry != list->end(); ++entry) { 51 scoped_ptr<base::Value> converted = 52 ConvertValue(**entry, schema.GetItems()); 53 if (converted) 54 result->Append(converted.release()); 55 } 56 return result.PassAs<base::Value>(); 57 } 58 return make_scoped_ptr(value.DeepCopy()).Pass(); 59 } 60 61 // Else, do some conversions to map windows registry data types to JSON types. 62 std::string string_value; 63 int int_value = 0; 64 switch (schema.type()) { 65 case base::Value::TYPE_NULL: { 66 return make_scoped_ptr(base::Value::CreateNullValue()).Pass(); 67 } 68 case base::Value::TYPE_BOOLEAN: { 69 // Accept booleans encoded as either string or integer. 70 if (value.GetAsInteger(&int_value) || 71 (value.GetAsString(&string_value) && 72 base::StringToInt(string_value, &int_value))) { 73 return scoped_ptr<base::Value>( 74 new base::FundamentalValue(int_value != 0)); 75 } 76 break; 77 } 78 case base::Value::TYPE_INTEGER: { 79 // Integers may be string-encoded. 80 if (value.GetAsString(&string_value) && 81 base::StringToInt(string_value, &int_value)) { 82 return scoped_ptr<base::Value>(new base::FundamentalValue(int_value)); 83 } 84 break; 85 } 86 case base::Value::TYPE_DOUBLE: { 87 // Doubles may be string-encoded or integer-encoded. 88 double double_value = 0; 89 if (value.GetAsDouble(&double_value) || 90 (value.GetAsString(&string_value) && 91 base::StringToDouble(string_value, &double_value))) { 92 return scoped_ptr<base::Value>( 93 new base::FundamentalValue(double_value)); 94 } 95 break; 96 } 97 case base::Value::TYPE_LIST: { 98 // Lists are encoded as subkeys with numbered value in the registry. 99 const base::DictionaryValue* dict = NULL; 100 if (value.GetAsDictionary(&dict)) { 101 scoped_ptr<base::ListValue> result(new base::ListValue()); 102 for (int i = 1; ; ++i) { 103 const base::Value* entry = NULL; 104 if (!dict->Get(base::IntToString(i), &entry)) 105 break; 106 scoped_ptr<base::Value> converted = 107 ConvertValue(*entry, schema.GetItems()); 108 if (converted) 109 result->Append(converted.release()); 110 } 111 return result.PassAs<base::Value>(); 112 } 113 // Fall through in order to accept lists encoded as JSON strings. 114 } 115 case base::Value::TYPE_DICTIONARY: { 116 // Dictionaries may be encoded as JSON strings. 117 if (value.GetAsString(&string_value)) { 118 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); 119 if (result && result->IsType(schema.type())) 120 return result.Pass(); 121 } 122 break; 123 } 124 case base::Value::TYPE_STRING: 125 case base::Value::TYPE_BINARY: 126 // No conversion possible. 127 break; 128 } 129 130 LOG(WARNING) << "Failed to convert " << value.GetType() 131 << " to " << schema.type(); 132 return scoped_ptr<base::Value>(); 133 } 134 135 } // namespace 136 137 bool CaseInsensitiveStringCompare::operator()(const std::string& a, 138 const std::string& b) const { 139 return base::strcasecmp(a.c_str(), b.c_str()) < 0; 140 } 141 142 RegistryDict::RegistryDict() {} 143 144 RegistryDict::~RegistryDict() { 145 ClearKeys(); 146 ClearValues(); 147 } 148 149 RegistryDict* RegistryDict::GetKey(const std::string& name) { 150 KeyMap::iterator entry = keys_.find(name); 151 return entry != keys_.end() ? entry->second : NULL; 152 } 153 154 const RegistryDict* RegistryDict::GetKey(const std::string& name) const { 155 KeyMap::const_iterator entry = keys_.find(name); 156 return entry != keys_.end() ? entry->second : NULL; 157 } 158 159 void RegistryDict::SetKey(const std::string& name, 160 scoped_ptr<RegistryDict> dict) { 161 if (!dict) { 162 RemoveKey(name); 163 return; 164 } 165 166 RegistryDict*& entry = keys_[name]; 167 delete entry; 168 entry = dict.release(); 169 } 170 171 scoped_ptr<RegistryDict> RegistryDict::RemoveKey(const std::string& name) { 172 scoped_ptr<RegistryDict> result; 173 KeyMap::iterator entry = keys_.find(name); 174 if (entry != keys_.end()) { 175 result.reset(entry->second); 176 keys_.erase(entry); 177 } 178 return result.Pass(); 179 } 180 181 void RegistryDict::ClearKeys() { 182 STLDeleteValues(&keys_); 183 } 184 185 base::Value* RegistryDict::GetValue(const std::string& name) { 186 ValueMap::iterator entry = values_.find(name); 187 return entry != values_.end() ? entry->second : NULL; 188 } 189 190 const base::Value* RegistryDict::GetValue(const std::string& name) const { 191 ValueMap::const_iterator entry = values_.find(name); 192 return entry != values_.end() ? entry->second : NULL; 193 } 194 195 void RegistryDict::SetValue(const std::string& name, 196 scoped_ptr<base::Value> dict) { 197 if (!dict) { 198 RemoveValue(name); 199 return; 200 } 201 202 base::Value*& entry = values_[name]; 203 delete entry; 204 entry = dict.release(); 205 } 206 207 scoped_ptr<base::Value> RegistryDict::RemoveValue(const std::string& name) { 208 scoped_ptr<base::Value> result; 209 ValueMap::iterator entry = values_.find(name); 210 if (entry != values_.end()) { 211 result.reset(entry->second); 212 values_.erase(entry); 213 } 214 return result.Pass(); 215 } 216 217 void RegistryDict::ClearValues() { 218 STLDeleteValues(&values_); 219 } 220 221 void RegistryDict::Merge(const RegistryDict& other) { 222 for (KeyMap::const_iterator entry(other.keys_.begin()); 223 entry != other.keys_.end(); ++entry) { 224 RegistryDict*& subdict = keys_[entry->first]; 225 if (!subdict) 226 subdict = new RegistryDict(); 227 subdict->Merge(*entry->second); 228 } 229 230 for (ValueMap::const_iterator entry(other.values_.begin()); 231 entry != other.values_.end(); ++entry) { 232 SetValue(entry->first, make_scoped_ptr(entry->second->DeepCopy()).Pass()); 233 } 234 } 235 236 void RegistryDict::Swap(RegistryDict* other) { 237 keys_.swap(other->keys_); 238 values_.swap(other->values_); 239 } 240 241 void RegistryDict::ReadRegistry(HKEY hive, const base::string16& root) { 242 ClearKeys(); 243 ClearValues(); 244 245 // First, read all the values of the key. 246 for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) { 247 const std::string name = base::UTF16ToUTF8(it.Name()); 248 switch (it.Type()) { 249 case REG_SZ: 250 case REG_EXPAND_SZ: 251 SetValue(name, 252 scoped_ptr<base::Value>( 253 new base::StringValue(base::UTF16ToUTF8(it.Value())))); 254 continue; 255 case REG_DWORD_LITTLE_ENDIAN: 256 case REG_DWORD_BIG_ENDIAN: 257 if (it.ValueSize() == sizeof(DWORD)) { 258 DWORD dword_value = *(reinterpret_cast<const DWORD*>(it.Value())); 259 if (it.Type() == REG_DWORD_BIG_ENDIAN) 260 dword_value = base::NetToHost32(dword_value); 261 else 262 dword_value = base::ByteSwapToLE32(dword_value); 263 SetValue(name, 264 scoped_ptr<base::Value>(new base::FundamentalValue( 265 static_cast<int>(dword_value)))); 266 continue; 267 } 268 case REG_NONE: 269 case REG_LINK: 270 case REG_MULTI_SZ: 271 case REG_RESOURCE_LIST: 272 case REG_FULL_RESOURCE_DESCRIPTOR: 273 case REG_RESOURCE_REQUIREMENTS_LIST: 274 case REG_QWORD_LITTLE_ENDIAN: 275 // Unsupported type, message gets logged below. 276 break; 277 } 278 279 LOG(WARNING) << "Failed to read hive " << hive << " at " 280 << root << "\\" << name 281 << " type " << it.Type(); 282 } 283 284 // Recurse for all subkeys. 285 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { 286 std::string name(base::UTF16ToUTF8(it.Name())); 287 scoped_ptr<RegistryDict> subdict(new RegistryDict()); 288 subdict->ReadRegistry(hive, root + L"\\" + it.Name()); 289 SetKey(name, subdict.Pass()); 290 } 291 } 292 293 scoped_ptr<base::Value> RegistryDict::ConvertToJSON( 294 const Schema& schema) const { 295 base::Value::Type type = 296 schema.valid() ? schema.type() : base::Value::TYPE_DICTIONARY; 297 switch (type) { 298 case base::Value::TYPE_DICTIONARY: { 299 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 300 for (RegistryDict::ValueMap::const_iterator entry(values_.begin()); 301 entry != values_.end(); ++entry) { 302 Schema subschema = 303 schema.valid() ? schema.GetProperty(entry->first) : Schema(); 304 scoped_ptr<base::Value> converted = 305 ConvertValue(*entry->second, subschema); 306 if (converted) 307 result->SetWithoutPathExpansion(entry->first, converted.release()); 308 } 309 for (RegistryDict::KeyMap::const_iterator entry(keys_.begin()); 310 entry != keys_.end(); ++entry) { 311 Schema subschema = 312 schema.valid() ? schema.GetProperty(entry->first) : Schema(); 313 scoped_ptr<base::Value> converted = 314 entry->second->ConvertToJSON(subschema); 315 if (converted) 316 result->SetWithoutPathExpansion(entry->first, converted.release()); 317 } 318 return result.PassAs<base::Value>(); 319 } 320 case base::Value::TYPE_LIST: { 321 scoped_ptr<base::ListValue> result(new base::ListValue()); 322 Schema item_schema = schema.valid() ? schema.GetItems() : Schema(); 323 for (int i = 1; ; ++i) { 324 const std::string name(base::IntToString(i)); 325 const RegistryDict* key = GetKey(name); 326 if (key) { 327 scoped_ptr<base::Value> converted = key->ConvertToJSON(item_schema); 328 if (converted) 329 result->Append(converted.release()); 330 continue; 331 } 332 const base::Value* value = GetValue(name); 333 if (value) { 334 scoped_ptr<base::Value> converted = ConvertValue(*value, item_schema); 335 if (converted) 336 result->Append(converted.release()); 337 continue; 338 } 339 break; 340 } 341 return result.PassAs<base::Value>(); 342 } 343 default: 344 LOG(WARNING) << "Can't convert registry key to schema type " << type; 345 } 346 347 return scoped_ptr<base::Value>(); 348 } 349 350 } // namespace policy 351