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 17using base::win::RegistryKeyIterator; 18using base::win::RegistryValueIterator; 19 20namespace policy { 21 22namespace { 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. 27scoped_ptr<base::Value> ConvertValue(const base::Value& value, 28 const Schema& schema) { 29 if (!schema.valid()) 30 return make_scoped_ptr(value.DeepCopy()); 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.Pass(); 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.Pass(); 57 } 58 return make_scoped_ptr(value.DeepCopy()); 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()); 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 make_scoped_ptr(base::Value::CreateBooleanValue(int_value != 0)); 74 } 75 break; 76 } 77 case base::Value::TYPE_INTEGER: { 78 // Integers may be string-encoded. 79 if (value.GetAsString(&string_value) && 80 base::StringToInt(string_value, &int_value)) { 81 return make_scoped_ptr(base::Value::CreateIntegerValue(int_value)); 82 } 83 break; 84 } 85 case base::Value::TYPE_DOUBLE: { 86 // Doubles may be string-encoded or integer-encoded. 87 double double_value = 0; 88 if (value.GetAsInteger(&int_value)) { 89 return make_scoped_ptr(base::Value::CreateDoubleValue(int_value)); 90 } else if (value.GetAsString(&string_value) && 91 base::StringToDouble(string_value, &double_value)) { 92 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); 93 } 94 break; 95 } 96 case base::Value::TYPE_LIST: { 97 // Lists are encoded as subkeys with numbered value in the registry. 98 const base::DictionaryValue* dict = NULL; 99 if (value.GetAsDictionary(&dict)) { 100 scoped_ptr<base::ListValue> result(new base::ListValue()); 101 for (int i = 1; ; ++i) { 102 const base::Value* entry = NULL; 103 if (!dict->Get(base::IntToString(i), &entry)) 104 break; 105 scoped_ptr<base::Value> converted = 106 ConvertValue(*entry, schema.GetItems()); 107 if (converted) 108 result->Append(converted.release()); 109 } 110 return result.Pass(); 111 } 112 // Fall through in order to accept lists encoded as JSON strings. 113 } 114 case base::Value::TYPE_DICTIONARY: { 115 // Dictionaries may be encoded as JSON strings. 116 if (value.GetAsString(&string_value)) { 117 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); 118 if (result && result->IsType(schema.type())) 119 return result.Pass(); 120 } 121 break; 122 } 123 case base::Value::TYPE_STRING: 124 case base::Value::TYPE_BINARY: 125 // No conversion possible. 126 break; 127 } 128 129 LOG(WARNING) << "Failed to convert " << value.GetType() 130 << " to " << schema.type(); 131 return scoped_ptr<base::Value>(); 132} 133 134} // namespace 135 136bool CaseInsensitiveStringCompare::operator()(const std::string& a, 137 const std::string& b) const { 138 return base::strcasecmp(a.c_str(), b.c_str()) < 0; 139} 140 141RegistryDict::RegistryDict() {} 142 143RegistryDict::~RegistryDict() { 144 ClearKeys(); 145 ClearValues(); 146} 147 148RegistryDict* RegistryDict::GetKey(const std::string& name) { 149 KeyMap::iterator entry = keys_.find(name); 150 return entry != keys_.end() ? entry->second : NULL; 151} 152 153const RegistryDict* RegistryDict::GetKey(const std::string& name) const { 154 KeyMap::const_iterator entry = keys_.find(name); 155 return entry != keys_.end() ? entry->second : NULL; 156} 157 158void RegistryDict::SetKey(const std::string& name, 159 scoped_ptr<RegistryDict> dict) { 160 if (!dict) { 161 RemoveKey(name); 162 return; 163 } 164 165 RegistryDict*& entry = keys_[name]; 166 delete entry; 167 entry = dict.release(); 168} 169 170scoped_ptr<RegistryDict> RegistryDict::RemoveKey(const std::string& name) { 171 scoped_ptr<RegistryDict> result; 172 KeyMap::iterator entry = keys_.find(name); 173 if (entry != keys_.end()) { 174 result.reset(entry->second); 175 keys_.erase(entry); 176 } 177 return result.Pass(); 178} 179 180void RegistryDict::ClearKeys() { 181 STLDeleteValues(&keys_); 182} 183 184base::Value* RegistryDict::GetValue(const std::string& name) { 185 ValueMap::iterator entry = values_.find(name); 186 return entry != values_.end() ? entry->second : NULL; 187} 188 189const base::Value* RegistryDict::GetValue(const std::string& name) const { 190 ValueMap::const_iterator entry = values_.find(name); 191 return entry != values_.end() ? entry->second : NULL; 192} 193 194void RegistryDict::SetValue(const std::string& name, 195 scoped_ptr<base::Value> dict) { 196 if (!dict) { 197 RemoveValue(name); 198 return; 199 } 200 201 base::Value*& entry = values_[name]; 202 delete entry; 203 entry = dict.release(); 204} 205 206scoped_ptr<base::Value> RegistryDict::RemoveValue(const std::string& name) { 207 scoped_ptr<base::Value> result; 208 ValueMap::iterator entry = values_.find(name); 209 if (entry != values_.end()) { 210 result.reset(entry->second); 211 values_.erase(entry); 212 } 213 return result.Pass(); 214} 215 216void RegistryDict::ClearValues() { 217 STLDeleteValues(&values_); 218} 219 220void RegistryDict::Merge(const RegistryDict& other) { 221 for (KeyMap::const_iterator entry(other.keys_.begin()); 222 entry != other.keys_.end(); ++entry) { 223 RegistryDict*& subdict = keys_[entry->first]; 224 if (!subdict) 225 subdict = new RegistryDict(); 226 subdict->Merge(*entry->second); 227 } 228 229 for (ValueMap::const_iterator entry(other.values_.begin()); 230 entry != other.values_.end(); ++entry) { 231 SetValue(entry->first, make_scoped_ptr(entry->second->DeepCopy())); 232 } 233} 234 235void RegistryDict::Swap(RegistryDict* other) { 236 keys_.swap(other->keys_); 237 values_.swap(other->values_); 238} 239 240void RegistryDict::ReadRegistry(HKEY hive, const base::string16& root) { 241 ClearKeys(); 242 ClearValues(); 243 244 // First, read all the values of the key. 245 for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) { 246 const std::string name = base::UTF16ToUTF8(it.Name()); 247 switch (it.Type()) { 248 case REG_SZ: 249 case REG_EXPAND_SZ: 250 SetValue( 251 name, 252 make_scoped_ptr( 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( 264 name, 265 make_scoped_ptr(base::Value::CreateIntegerValue(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 293scoped_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.Pass(); 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.Pass(); 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