| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/policy/core/common/registry_dict_win.h" | 5 #include "components/policy/core/common/registry_dict_win.h" |
| 6 | 6 |
| 7 #include "base/json/json_reader.h" | 7 #include "base/json/json_reader.h" |
| 8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/sys_byteorder.h" | 12 #include "base/sys_byteorder.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "base/win/registry.h" | 14 #include "base/win/registry.h" |
| 15 #include "components/json_schema/json_schema_constants.h" | 15 #include "components/policy/core/common/schema.h" |
| 16 | |
| 17 namespace schema = json_schema_constants; | |
| 18 | 16 |
| 19 using base::win::RegistryKeyIterator; | 17 using base::win::RegistryKeyIterator; |
| 20 using base::win::RegistryValueIterator; | 18 using base::win::RegistryValueIterator; |
| 21 | 19 |
| 22 namespace policy { | 20 namespace policy { |
| 23 | 21 |
| 24 namespace { | 22 namespace { |
| 25 | 23 |
| 26 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL. | |
| 27 const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary, | |
| 28 const std::string& name) { | |
| 29 if (!dictionary) | |
| 30 return NULL; | |
| 31 const base::DictionaryValue* entry = NULL; | |
| 32 dictionary->GetDictionaryWithoutPathExpansion(name, &entry); | |
| 33 return entry; | |
| 34 } | |
| 35 | |
| 36 // Returns the Value type described in |schema|, or |default_type| if not found. | |
| 37 base::Value::Type GetValueTypeForSchema(const base::DictionaryValue* schema, | |
| 38 base::Value::Type default_type) { | |
| 39 // JSON-schema types to base::Value::Type mapping. | |
| 40 static const struct { | |
| 41 // JSON schema type. | |
| 42 const char* schema_type; | |
| 43 // Correspondent value type. | |
| 44 base::Value::Type value_type; | |
| 45 } kSchemaToValueTypeMap[] = { | |
| 46 { schema::kArray, base::Value::TYPE_LIST }, | |
| 47 { schema::kBoolean, base::Value::TYPE_BOOLEAN }, | |
| 48 { schema::kInteger, base::Value::TYPE_INTEGER }, | |
| 49 { schema::kNull, base::Value::TYPE_NULL }, | |
| 50 { schema::kNumber, base::Value::TYPE_DOUBLE }, | |
| 51 { schema::kObject, base::Value::TYPE_DICTIONARY }, | |
| 52 { schema::kString, base::Value::TYPE_STRING }, | |
| 53 }; | |
| 54 | |
| 55 if (!schema) | |
| 56 return default_type; | |
| 57 std::string type; | |
| 58 if (!schema->GetStringWithoutPathExpansion(schema::kType, &type)) | |
| 59 return default_type; | |
| 60 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { | |
| 61 if (type == kSchemaToValueTypeMap[i].schema_type) | |
| 62 return kSchemaToValueTypeMap[i].value_type; | |
| 63 } | |
| 64 return default_type; | |
| 65 } | |
| 66 | |
| 67 // Returns the schema for property |name| given the |schema| of an object. | |
| 68 // Returns the "additionalProperties" schema if no specific schema for | |
| 69 // |name| is present. Returns NULL if no schema is found. | |
| 70 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, | |
| 71 const std::string& name) { | |
| 72 const base::DictionaryValue* properties = | |
| 73 GetEntry(schema, schema::kProperties); | |
| 74 const base::DictionaryValue* sub_schema = GetEntry(properties, name); | |
| 75 if (sub_schema) | |
| 76 return sub_schema; | |
| 77 // "additionalProperties" can be a boolean, but that case is ignored. | |
| 78 return GetEntry(schema, schema::kAdditionalProperties); | |
| 79 } | |
| 80 | |
| 81 // Converts a value (as read from the registry) to meet |schema|, converting | 24 // Converts a value (as read from the registry) to meet |schema|, converting |
| 82 // types as necessary. Unconvertible types will show up as NULL values in the | 25 // types as necessary. Unconvertible types will show up as NULL values in the |
| 83 // result. | 26 // result. |
| 84 scoped_ptr<base::Value> ConvertValue(const base::Value& value, | 27 scoped_ptr<base::Value> ConvertValue(const base::Value& value, |
| 85 const base::DictionaryValue* schema) { | 28 const Schema& schema) { |
| 86 // Figure out the type to convert to from the schema. | 29 if (!schema.valid()) |
| 87 const base::Value::Type result_type( | 30 return make_scoped_ptr(value.DeepCopy()); |
| 88 GetValueTypeForSchema(schema, value.GetType())); | |
| 89 | 31 |
| 90 // If the type is good already, go with it. | 32 // If the type is good already, go with it. |
| 91 if (value.IsType(result_type)) { | 33 if (value.IsType(schema.type())) { |
| 92 // Recurse for complex types if there is a schema. | 34 // Recurse for complex types. |
| 93 if (schema) { | 35 const base::DictionaryValue* dict = NULL; |
| 94 const base::DictionaryValue* dict = NULL; | 36 const base::ListValue* list = NULL; |
| 95 const base::ListValue* list = NULL; | 37 if (value.GetAsDictionary(&dict)) { |
| 96 if (value.GetAsDictionary(&dict)) { | 38 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 97 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 39 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); |
| 98 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); | 40 entry.Advance()) { |
| 99 entry.Advance()) { | 41 scoped_ptr<base::Value> converted_value( |
| 100 scoped_ptr<base::Value> converted_value( | 42 ConvertValue(entry.value(), schema.GetProperty(entry.key()))); |
| 101 ConvertValue(entry.value(), GetSchemaFor(schema, entry.key()))); | 43 result->SetWithoutPathExpansion(entry.key(), |
| 102 result->SetWithoutPathExpansion(entry.key(), | 44 converted_value.release()); |
| 103 converted_value.release()); | |
| 104 } | |
| 105 return result.Pass(); | |
| 106 } else if (value.GetAsList(&list)) { | |
| 107 scoped_ptr<base::ListValue> result(new base::ListValue()); | |
| 108 const base::DictionaryValue* item_schema = | |
| 109 GetEntry(schema, schema::kItems); | |
| 110 for (base::ListValue::const_iterator entry(list->begin()); | |
| 111 entry != list->end(); ++entry) { | |
| 112 result->Append(ConvertValue(**entry, item_schema).release()); | |
| 113 } | |
| 114 return result.Pass(); | |
| 115 } | 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 result->Append(ConvertValue(**entry, schema.GetItems()).release()); |
| 52 } |
| 53 return result.Pass(); |
| 116 } | 54 } |
| 117 return make_scoped_ptr(value.DeepCopy()); | 55 return make_scoped_ptr(value.DeepCopy()); |
| 118 } | 56 } |
| 119 | 57 |
| 120 // Else, do some conversions to map windows registry data types to JSON types. | 58 // Else, do some conversions to map windows registry data types to JSON types. |
| 121 std::string string_value; | 59 std::string string_value; |
| 122 int int_value = 0; | 60 int int_value = 0; |
| 123 switch (result_type) { | 61 switch (schema.type()) { |
| 124 case base::Value::TYPE_NULL: { | 62 case base::Value::TYPE_NULL: { |
| 125 return make_scoped_ptr(base::Value::CreateNullValue()); | 63 return make_scoped_ptr(base::Value::CreateNullValue()); |
| 126 } | 64 } |
| 127 case base::Value::TYPE_BOOLEAN: { | 65 case base::Value::TYPE_BOOLEAN: { |
| 128 // Accept booleans encoded as either string or integer. | 66 // Accept booleans encoded as either string or integer. |
| 129 if (value.GetAsInteger(&int_value) || | 67 if (value.GetAsInteger(&int_value) || |
| 130 (value.GetAsString(&string_value) && | 68 (value.GetAsString(&string_value) && |
| 131 base::StringToInt(string_value, &int_value))) { | 69 base::StringToInt(string_value, &int_value))) { |
| 132 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0)); | 70 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0)); |
| 133 } | 71 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 150 base::StringToDouble(string_value, &double_value)) { | 88 base::StringToDouble(string_value, &double_value)) { |
| 151 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); | 89 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); |
| 152 } | 90 } |
| 153 break; | 91 break; |
| 154 } | 92 } |
| 155 case base::Value::TYPE_LIST: { | 93 case base::Value::TYPE_LIST: { |
| 156 // Lists are encoded as subkeys with numbered value in the registry. | 94 // Lists are encoded as subkeys with numbered value in the registry. |
| 157 const base::DictionaryValue* dict = NULL; | 95 const base::DictionaryValue* dict = NULL; |
| 158 if (value.GetAsDictionary(&dict)) { | 96 if (value.GetAsDictionary(&dict)) { |
| 159 scoped_ptr<base::ListValue> result(new base::ListValue()); | 97 scoped_ptr<base::ListValue> result(new base::ListValue()); |
| 160 const base::DictionaryValue* item_schema = | |
| 161 GetEntry(schema, schema::kItems); | |
| 162 for (int i = 1; ; ++i) { | 98 for (int i = 1; ; ++i) { |
| 163 const base::Value* entry = NULL; | 99 const base::Value* entry = NULL; |
| 164 if (!dict->Get(base::IntToString(i), &entry)) | 100 if (!dict->Get(base::IntToString(i), &entry)) |
| 165 break; | 101 break; |
| 166 result->Append(ConvertValue(*entry, item_schema).release()); | 102 result->Append(ConvertValue(*entry, schema.GetItems()).release()); |
| 167 } | 103 } |
| 168 return result.Pass(); | 104 return result.Pass(); |
| 169 } | 105 } |
| 170 // Fall through in order to accept lists encoded as JSON strings. | 106 // Fall through in order to accept lists encoded as JSON strings. |
| 171 } | 107 } |
| 172 case base::Value::TYPE_DICTIONARY: { | 108 case base::Value::TYPE_DICTIONARY: { |
| 173 // Dictionaries may be encoded as JSON strings. | 109 // Dictionaries may be encoded as JSON strings. |
| 174 if (value.GetAsString(&string_value)) { | 110 if (value.GetAsString(&string_value)) { |
| 175 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); | 111 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); |
| 176 if (result && result->IsType(result_type)) | 112 if (result && result->IsType(schema.type())) |
| 177 return result.Pass(); | 113 return result.Pass(); |
| 178 } | 114 } |
| 179 break; | 115 break; |
| 180 } | 116 } |
| 181 case base::Value::TYPE_STRING: | 117 case base::Value::TYPE_STRING: |
| 182 case base::Value::TYPE_BINARY: | 118 case base::Value::TYPE_BINARY: |
| 183 // No conversion possible. | 119 // No conversion possible. |
| 184 break; | 120 break; |
| 185 } | 121 } |
| 186 | 122 |
| 187 LOG(WARNING) << "Failed to convert " << value.GetType() | 123 LOG(WARNING) << "Failed to convert " << value.GetType() |
| 188 << " to " << result_type; | 124 << " to " << schema.type(); |
| 189 return make_scoped_ptr(base::Value::CreateNullValue()); | 125 return make_scoped_ptr(base::Value::CreateNullValue()); |
| 190 } | 126 } |
| 191 | 127 |
| 192 } // namespace | 128 } // namespace |
| 193 | 129 |
| 194 bool CaseInsensitiveStringCompare::operator()(const std::string& a, | 130 bool CaseInsensitiveStringCompare::operator()(const std::string& a, |
| 195 const std::string& b) const { | 131 const std::string& b) const { |
| 196 return base::strcasecmp(a.c_str(), b.c_str()) < 0; | 132 return base::strcasecmp(a.c_str(), b.c_str()) < 0; |
| 197 } | 133 } |
| 198 | 134 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 // Recurse for all subkeys. | 277 // Recurse for all subkeys. |
| 342 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { | 278 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { |
| 343 std::string name(UTF16ToUTF8(it.Name())); | 279 std::string name(UTF16ToUTF8(it.Name())); |
| 344 scoped_ptr<RegistryDict> subdict(new RegistryDict()); | 280 scoped_ptr<RegistryDict> subdict(new RegistryDict()); |
| 345 subdict->ReadRegistry(hive, root + L"\\" + it.Name()); | 281 subdict->ReadRegistry(hive, root + L"\\" + it.Name()); |
| 346 SetKey(name, subdict.Pass()); | 282 SetKey(name, subdict.Pass()); |
| 347 } | 283 } |
| 348 } | 284 } |
| 349 | 285 |
| 350 scoped_ptr<base::Value> RegistryDict::ConvertToJSON( | 286 scoped_ptr<base::Value> RegistryDict::ConvertToJSON( |
| 351 const base::DictionaryValue* schema) const { | 287 const Schema& schema) const { |
| 352 base::Value::Type type = | 288 base::Value::Type type = |
| 353 GetValueTypeForSchema(schema, base::Value::TYPE_DICTIONARY); | 289 schema.valid() ? schema.type() : base::Value::TYPE_DICTIONARY; |
| 354 switch (type) { | 290 switch (type) { |
| 355 case base::Value::TYPE_DICTIONARY: { | 291 case base::Value::TYPE_DICTIONARY: { |
| 356 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 292 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 357 for (RegistryDict::ValueMap::const_iterator entry(values_.begin()); | 293 for (RegistryDict::ValueMap::const_iterator entry(values_.begin()); |
| 358 entry != values_.end(); ++entry) { | 294 entry != values_.end(); ++entry) { |
| 295 Schema subschema = |
| 296 schema.valid() ? schema.GetProperty(entry->first) : Schema(); |
| 359 result->SetWithoutPathExpansion( | 297 result->SetWithoutPathExpansion( |
| 360 entry->first, | 298 entry->first, |
| 361 ConvertValue(*entry->second, | 299 ConvertValue(*entry->second, subschema).release()); |
| 362 GetSchemaFor(schema, entry->first)).release()); | |
| 363 } | 300 } |
| 364 for (RegistryDict::KeyMap::const_iterator entry(keys_.begin()); | 301 for (RegistryDict::KeyMap::const_iterator entry(keys_.begin()); |
| 365 entry != keys_.end(); ++entry) { | 302 entry != keys_.end(); ++entry) { |
| 303 Schema subschema = |
| 304 schema.valid() ? schema.GetProperty(entry->first) : Schema(); |
| 366 result->SetWithoutPathExpansion( | 305 result->SetWithoutPathExpansion( |
| 367 entry->first, | 306 entry->first, |
| 368 entry->second->ConvertToJSON( | 307 entry->second->ConvertToJSON(subschema).release()); |
| 369 GetSchemaFor(schema, entry->first)).release()); | |
| 370 } | 308 } |
| 371 return result.Pass(); | 309 return result.Pass(); |
| 372 } | 310 } |
| 373 case base::Value::TYPE_LIST: { | 311 case base::Value::TYPE_LIST: { |
| 374 scoped_ptr<base::ListValue> result(new base::ListValue()); | 312 scoped_ptr<base::ListValue> result(new base::ListValue()); |
| 375 const base::DictionaryValue* item_schema = | 313 Schema item_schema = schema.valid() ? schema.GetItems() : Schema(); |
| 376 GetEntry(schema, schema::kItems); | |
| 377 for (int i = 1; ; ++i) { | 314 for (int i = 1; ; ++i) { |
| 378 const std::string name(base::IntToString(i)); | 315 const std::string name(base::IntToString(i)); |
| 379 const RegistryDict* key = GetKey(name); | 316 const RegistryDict* key = GetKey(name); |
| 380 if (key) { | 317 if (key) { |
| 381 result->Append(key->ConvertToJSON(item_schema).release()); | 318 result->Append(key->ConvertToJSON(item_schema).release()); |
| 382 continue; | 319 continue; |
| 383 } | 320 } |
| 384 const base::Value* value = GetValue(name); | 321 const base::Value* value = GetValue(name); |
| 385 if (value) { | 322 if (value) { |
| 386 result->Append(ConvertValue(*value, item_schema).release()); | 323 result->Append(ConvertValue(*value, item_schema).release()); |
| 387 continue; | 324 continue; |
| 388 } | 325 } |
| 389 break; | 326 break; |
| 390 } | 327 } |
| 391 return result.Pass(); | 328 return result.Pass(); |
| 392 } | 329 } |
| 393 default: | 330 default: |
| 394 LOG(WARNING) << "Can't convert registry key to schema type " << type; | 331 LOG(WARNING) << "Can't convert registry key to schema type " << type; |
| 395 } | 332 } |
| 396 | 333 |
| 397 return make_scoped_ptr(base::Value::CreateNullValue()); | 334 return make_scoped_ptr(base::Value::CreateNullValue()); |
| 398 } | 335 } |
| 399 | 336 |
| 400 } // namespace policy | 337 } // namespace policy |
| OLD | NEW |