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 |