OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/policy/policy_loader_win.h" | 5 #include "chrome/browser/policy/policy_loader_win.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include <string.h> | 9 #include <string.h> |
10 | 10 |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "base/utf_string_conversions.h" | 22 #include "base/utf_string_conversions.h" |
23 #include "base/values.h" | 23 #include "base/values.h" |
24 #include "base/win/registry.h" | 24 #include "base/win/registry.h" |
25 #include "chrome/browser/policy/policy_bundle.h" | 25 #include "chrome/browser/policy/policy_bundle.h" |
26 #include "chrome/browser/policy/policy_map.h" | 26 #include "chrome/browser/policy/policy_map.h" |
27 #include "policy/policy_constants.h" | 27 #include "policy/policy_constants.h" |
28 | 28 |
29 using base::win::RegKey; | 29 using base::win::RegKey; |
30 using base::win::RegistryKeyIterator; | 30 using base::win::RegistryKeyIterator; |
31 using base::win::RegistryValueIterator; | 31 using base::win::RegistryValueIterator; |
| 32 using namespace policy::registry_constants; |
32 | 33 |
33 namespace policy { | 34 namespace policy { |
34 | 35 |
| 36 namespace registry_constants { |
| 37 const wchar_t kPathSep[] = L"\\"; |
| 38 const wchar_t kThirdParty[] = L"3rdparty"; |
| 39 const wchar_t kMandatory[] = L"policy"; |
| 40 const wchar_t kRecommended[] = L"recommended"; |
| 41 const wchar_t kSchema[] = L"schema"; |
| 42 const char kType[] = "type"; |
| 43 const char kProperties[] = "properties"; |
| 44 const char kAdditionalProperties[] = "additionalProperties"; |
| 45 const char kItems[] = "items"; |
| 46 } // namespace registry_constants |
| 47 |
35 namespace { | 48 namespace { |
36 | 49 |
37 // Suffix of kRegistryMandatorySubKey where 3rd party policies are stored. | |
38 const char k3rdPartyPolicySubKey[] = "\\3rdparty\\"; | |
39 | |
40 // Path separator for registry keys. | |
41 const wchar_t kPathSep[] = L"\\"; | |
42 | |
43 // Map of registry hives to their corresponding policy scope, in decreasing | 50 // Map of registry hives to their corresponding policy scope, in decreasing |
44 // order of priority. | 51 // order of priority. |
45 const struct { | 52 const struct { |
46 HKEY hive; | 53 HKEY hive; |
47 PolicyScope scope; | 54 PolicyScope scope; |
48 } kHives[] = { | 55 } kHives[] = { |
49 { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, | 56 { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, |
50 { HKEY_CURRENT_USER, POLICY_SCOPE_USER }, | 57 { HKEY_CURRENT_USER, POLICY_SCOPE_USER }, |
51 }; | 58 }; |
52 | 59 |
(...skipping 20 matching lines...) Expand all Loading... |
73 { kRegistryMandatorySubKey, POLICY_LEVEL_MANDATORY }, | 80 { kRegistryMandatorySubKey, POLICY_LEVEL_MANDATORY }, |
74 { kRegistryRecommendedSubKey, POLICY_LEVEL_RECOMMENDED }, | 81 { kRegistryRecommendedSubKey, POLICY_LEVEL_RECOMMENDED }, |
75 }; | 82 }; |
76 | 83 |
77 // Lookup at the mandatory path for both user and machine policies first, and | 84 // Lookup at the mandatory path for both user and machine policies first, and |
78 // then at the recommended path. | 85 // then at the recommended path. |
79 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { | 86 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { |
80 for (size_t h = 0; h < arraysize(kHives); ++h) { | 87 for (size_t h = 0; h < arraysize(kHives); ++h) { |
81 string16 path(kKeyPaths[k].path); | 88 string16 path(kKeyPaths[k].path); |
82 if (!key_path.empty()) | 89 if (!key_path.empty()) |
83 path += ASCIIToUTF16("\\") + key_path; | 90 path += kPathSep + key_path; |
84 key->Open(kHives[h].hive, path.c_str(), KEY_READ); | 91 key->Open(kHives[h].hive, path.c_str(), KEY_READ); |
85 if (!key->Valid()) | 92 if (!key->Valid()) |
86 continue; | 93 continue; |
87 if (value_name.empty() || key->HasValue(value_name.c_str())) { | 94 if (value_name.empty() || key->HasValue(value_name.c_str())) { |
88 *level = kKeyPaths[k].level; | 95 *level = kKeyPaths[k].level; |
89 *scope = kHives[h].scope; | 96 *scope = kHives[h].scope; |
90 return true; | 97 return true; |
91 } | 98 } |
92 } | 99 } |
93 } | 100 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 uint32* result) { | 133 uint32* result) { |
127 DWORD dword; | 134 DWORD dword; |
128 if (key->ReadValueDW(name.c_str(), &dword) != ERROR_SUCCESS) | 135 if (key->ReadValueDW(name.c_str(), &dword) != ERROR_SUCCESS) |
129 return false; | 136 return false; |
130 *result = dword; | 137 *result = dword; |
131 return true; | 138 return true; |
132 } | 139 } |
133 | 140 |
134 // Returns the Value for a Chrome string policy named |name|, or NULL if | 141 // Returns the Value for a Chrome string policy named |name|, or NULL if |
135 // it wasn't found. The caller owns the returned value. | 142 // it wasn't found. The caller owns the returned value. |
136 base::Value* ReadStringValue(const string16& name, | 143 base::Value* ReadChromeStringValue(const string16& name, |
137 PolicyLevel* level, | 144 PolicyLevel* level, |
138 PolicyScope* scope) { | 145 PolicyScope* scope) { |
139 RegKey key; | 146 RegKey key; |
140 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) | 147 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) |
141 return NULL; | 148 return NULL; |
142 string16 value; | 149 string16 value; |
143 if (!ReadRegistryString(&key, name, &value)) | 150 if (!ReadRegistryString(&key, name, &value)) |
144 return NULL; | 151 return NULL; |
145 return base::Value::CreateStringValue(value); | 152 return base::Value::CreateStringValue(value); |
146 } | 153 } |
147 | 154 |
148 // Returns the Value for a Chrome string list policy named |name|, | 155 // Returns the Value for a Chrome string list policy named |name|, |
149 // or NULL if it wasn't found. The caller owns the returned value. | 156 // or NULL if it wasn't found. The caller owns the returned value. |
150 base::Value* ReadStringListValue(const string16& name, | 157 base::Value* ReadChromeStringListValue(const string16& name, |
151 PolicyLevel* level, | 158 PolicyLevel* level, |
152 PolicyScope* scope) { | 159 PolicyScope* scope) { |
153 RegKey key; | 160 RegKey key; |
154 if (!LoadHighestPriorityKey(name, string16(), &key, level, scope)) | 161 if (!LoadHighestPriorityKey(name, string16(), &key, level, scope)) |
155 return NULL; | 162 return NULL; |
156 base::ListValue* result = new base::ListValue(); | 163 base::ListValue* result = new base::ListValue(); |
157 string16 value; | 164 string16 value; |
158 int index = 0; | 165 int index = 0; |
159 while (ReadRegistryString(&key, base::IntToString16(++index), &value)) | 166 while (ReadRegistryString(&key, base::IntToString16(++index), &value)) |
160 result->Append(base::Value::CreateStringValue(value)); | 167 result->Append(base::Value::CreateStringValue(value)); |
161 return result; | 168 return result; |
162 } | 169 } |
163 | 170 |
164 // Returns the Value for a Chrome boolean policy named |name|, | 171 // Returns the Value for a Chrome boolean policy named |name|, |
165 // or NULL if it wasn't found. The caller owns the returned value. | 172 // or NULL if it wasn't found. The caller owns the returned value. |
166 base::Value* ReadBooleanValue(const string16& name, | 173 base::Value* ReadChromeBooleanValue(const string16& name, |
167 PolicyLevel* level, | 174 PolicyLevel* level, |
168 PolicyScope* scope) { | 175 PolicyScope* scope) { |
169 RegKey key; | 176 RegKey key; |
170 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) | 177 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) |
171 return NULL; | 178 return NULL; |
172 uint32 value; | 179 uint32 value; |
173 if (!ReadRegistryInteger(&key, name, &value)) | 180 if (!ReadRegistryInteger(&key, name, &value)) |
174 return NULL; | 181 return NULL; |
175 return base::Value::CreateBooleanValue(value != 0u); | 182 return base::Value::CreateBooleanValue(value != 0u); |
176 } | 183 } |
177 | 184 |
178 // Returns the Value for a Chrome integer policy named |name|, | 185 // Returns the Value for a Chrome integer policy named |name|, |
179 // or NULL if it wasn't found. The caller owns the returned value. | 186 // or NULL if it wasn't found. The caller owns the returned value. |
180 base::Value* ReadIntegerValue(const string16& name, | 187 base::Value* ReadChromeIntegerValue(const string16& name, |
181 PolicyLevel* level, | 188 PolicyLevel* level, |
182 PolicyScope* scope) { | 189 PolicyScope* scope) { |
183 RegKey key; | 190 RegKey key; |
184 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) | 191 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) |
185 return NULL; | 192 return NULL; |
186 uint32 value; | 193 uint32 value; |
187 if (!ReadRegistryInteger(&key, name, &value)) | 194 if (!ReadRegistryInteger(&key, name, &value)) |
188 return NULL; | 195 return NULL; |
189 return base::Value::CreateIntegerValue(value); | 196 return base::Value::CreateIntegerValue(value); |
190 } | 197 } |
191 | 198 |
192 // Returns the Value for a Chrome dictionary policy named |name|, | 199 // Returns the Value for a Chrome dictionary policy named |name|, |
193 // or NULL if it wasn't found. The caller owns the returned value. | 200 // or NULL if it wasn't found. The caller owns the returned value. |
194 base::Value* ReadDictionaryValue(const string16& name, | 201 base::Value* ReadChromeDictionaryValue(const string16& name, |
195 PolicyLevel* level, | 202 PolicyLevel* level, |
196 PolicyScope* scope) { | 203 PolicyScope* scope) { |
197 // Dictionaries are encoded as JSON strings on Windows. | 204 // Dictionaries are encoded as JSON strings on Windows. |
198 // | 205 // |
199 // A dictionary could be stored as a subkey, with each of its entries | 206 // A dictionary could be stored as a subkey, with each of its entries |
200 // within that subkey. However, it would be impossible to recover the | 207 // within that subkey. However, it would be impossible to recover the |
201 // type for some of those entries: | 208 // type for some of those entries: |
202 // - Booleans are stored as DWORDS and are indistinguishable from | 209 // - Booleans are stored as DWORDS and are indistinguishable from |
203 // integers; | 210 // integers; |
204 // - Lists are stored as a subkey, with entries mapping 0 to N-1 to | 211 // - Lists are stored as a subkey, with entries mapping 0 to N-1 to |
205 // their value. This is indistinguishable from a Dictionary with | 212 // their value. This is indistinguishable from a Dictionary with |
206 // integer keys. | 213 // integer keys. |
207 // | 214 // |
208 // The GPO policy editor also has a limited data entry form that doesn't | 215 // The GPO policy editor also has a limited data entry form that doesn't |
209 // support dictionaries. | 216 // support dictionaries. |
210 RegKey key; | 217 RegKey key; |
211 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) | 218 if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) |
212 return NULL; | 219 return NULL; |
213 string16 value; | 220 string16 value; |
214 if (!ReadRegistryString(&key, name, &value)) | 221 if (!ReadRegistryString(&key, name, &value)) |
215 return NULL; | 222 return NULL; |
216 return base::JSONReader::Read(UTF16ToUTF8(value)); | 223 return base::JSONReader::Read(UTF16ToUTF8(value)); |
217 } | 224 } |
218 | 225 |
219 // Loads the dictionary at |path| in the given |hive|. Ownership is transferred | 226 // Returns the Value type described in |schema|, or |default_type| if not found. |
220 // to the caller. | 227 base::Value::Type GetType(const base::DictionaryValue* schema, |
221 base::DictionaryValue* ReadRegistryDictionaryValue(HKEY hive, | 228 base::Value::Type default_type) { |
222 const string16& path) { | 229 // JSON-schema types to base::Value::Type mapping. |
| 230 static const struct { |
| 231 // JSON schema type. |
| 232 const char* schema_type; |
| 233 // Correspondent value type. |
| 234 base::Value::Type value_type; |
| 235 } kSchemaToValueTypeMap[] = { |
| 236 { "array", base::Value::TYPE_LIST }, |
| 237 { "boolean", base::Value::TYPE_BOOLEAN }, |
| 238 { "integer", base::Value::TYPE_INTEGER }, |
| 239 { "null", base::Value::TYPE_NULL }, |
| 240 { "number", base::Value::TYPE_DOUBLE }, |
| 241 { "object", base::Value::TYPE_DICTIONARY }, |
| 242 { "string", base::Value::TYPE_STRING }, |
| 243 }; |
| 244 |
| 245 if (!schema) |
| 246 return default_type; |
| 247 std::string type; |
| 248 if (!schema->GetString(kType, &type)) |
| 249 return default_type; |
| 250 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { |
| 251 if (type == kSchemaToValueTypeMap[i].schema_type) |
| 252 return kSchemaToValueTypeMap[i].value_type; |
| 253 } |
| 254 return default_type; |
| 255 } |
| 256 |
| 257 // Returns the default type for registry entries of |reg_type|, when there is |
| 258 // no schema defined type for a policy. |
| 259 base::Value::Type GetDefaultFor(DWORD reg_type) { |
| 260 return reg_type == REG_DWORD ? base::Value::TYPE_INTEGER : |
| 261 base::Value::TYPE_STRING; |
| 262 } |
| 263 |
| 264 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL. |
| 265 base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary, |
| 266 const std::string& name) { |
| 267 if (!dictionary) |
| 268 return NULL; |
| 269 base::DictionaryValue* entry = NULL; |
| 270 dictionary->GetDictionary(name, &entry); |
| 271 return entry; |
| 272 } |
| 273 |
| 274 // Returns the schema for property |name| given the |schema| of an object. |
| 275 // Returns the "additionalProperties" schema if no specific schema for |
| 276 // |name| is present. Returns NULL if no schema is found. |
| 277 base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, |
| 278 const std::string& name) { |
| 279 base::DictionaryValue* properties = GetEntry(schema, kProperties); |
| 280 base::DictionaryValue* sub_schema = GetEntry(properties, name); |
| 281 if (sub_schema) |
| 282 return sub_schema; |
| 283 // "additionalProperties" can be a boolean, but that case is ignored. |
| 284 return GetEntry(schema, kAdditionalProperties); |
| 285 } |
| 286 |
| 287 // Converts string |value| to another |type|, if possible. |
| 288 base::Value* ConvertComponentStringValue(const string16& value, |
| 289 base::Value::Type type) { |
| 290 switch (type) { |
| 291 case base::Value::TYPE_NULL: |
| 292 return base::Value::CreateNullValue(); |
| 293 |
| 294 case base::Value::TYPE_BOOLEAN: { |
| 295 int int_value; |
| 296 if (base::StringToInt(value, &int_value)) |
| 297 return base::Value::CreateBooleanValue(int_value != 0); |
| 298 return NULL; |
| 299 } |
| 300 |
| 301 case base::Value::TYPE_INTEGER: { |
| 302 int int_value; |
| 303 if (base::StringToInt(value, &int_value)) |
| 304 return base::Value::CreateIntegerValue(int_value); |
| 305 return NULL; |
| 306 } |
| 307 |
| 308 case base::Value::TYPE_DOUBLE: { |
| 309 double double_value; |
| 310 if (base::StringToDouble(UTF16ToUTF8(value), &double_value)) |
| 311 return base::Value::CreateDoubleValue(double_value); |
| 312 DLOG(WARNING) << "Failed to read policy value as double: " << value; |
| 313 return NULL; |
| 314 } |
| 315 |
| 316 case base::Value::TYPE_STRING: |
| 317 return base::Value::CreateStringValue(value); |
| 318 |
| 319 case base::Value::TYPE_DICTIONARY: |
| 320 case base::Value::TYPE_LIST: |
| 321 return base::JSONReader::Read(UTF16ToUTF8(value)); |
| 322 |
| 323 case base::Value::TYPE_BINARY: |
| 324 DLOG(WARNING) << "Cannot convert REG_SZ entry to type " << type; |
| 325 return NULL; |
| 326 } |
| 327 NOTREACHED(); |
| 328 return NULL; |
| 329 } |
| 330 |
| 331 // Converts an integer |value| to another |type|, if possible. |
| 332 base::Value* ConvertComponentIntegerValue(uint32 value, |
| 333 base::Value::Type type) { |
| 334 switch (type) { |
| 335 case base::Value::TYPE_BOOLEAN: |
| 336 return base::Value::CreateBooleanValue(value != 0); |
| 337 |
| 338 case base::Value::TYPE_INTEGER: |
| 339 return base::Value::CreateIntegerValue(value); |
| 340 |
| 341 case base::Value::TYPE_DOUBLE: |
| 342 return base::Value::CreateDoubleValue(value); |
| 343 |
| 344 case base::Value::TYPE_NULL: |
| 345 case base::Value::TYPE_STRING: |
| 346 case base::Value::TYPE_BINARY: |
| 347 case base::Value::TYPE_DICTIONARY: |
| 348 case base::Value::TYPE_LIST: |
| 349 DLOG(WARNING) << "Cannot convert REG_DWORD entry to type " << type; |
| 350 return NULL; |
| 351 } |
| 352 NOTREACHED(); |
| 353 return NULL; |
| 354 } |
| 355 |
| 356 // Reads a simple (non-Dictionary, non-Array) value from the registry |key| |
| 357 // named |name| with registry type |reg_type| as a value of type |type|. |
| 358 // Returns NULL if the value could not be loaded or converted. |
| 359 base::Value* ReadComponentSimpleValue(RegKey* key, |
| 360 const string16& name, |
| 361 DWORD reg_type, |
| 362 base::Value::Type type) { |
| 363 switch (reg_type) { |
| 364 case REG_SZ: { |
| 365 string16 value; |
| 366 if (ReadRegistryString(key, name, &value)) |
| 367 return ConvertComponentStringValue(value, type); |
| 368 break; |
| 369 } |
| 370 |
| 371 case REG_DWORD: { |
| 372 uint32 value; |
| 373 if (ReadRegistryInteger(key, name, &value)) |
| 374 return ConvertComponentIntegerValue(value, type); |
| 375 break; |
| 376 } |
| 377 |
| 378 default: |
| 379 DLOG(WARNING) << "Registry type not supported for key " << name; |
| 380 break; |
| 381 } |
| 382 NOTREACHED(); |
| 383 return NULL; |
| 384 } |
| 385 |
| 386 // Forward declaration for ReadComponentListValue(). |
| 387 base::DictionaryValue* ReadComponentDictionaryValue( |
| 388 HKEY hive, |
| 389 const string16& path, |
| 390 const base::DictionaryValue* schema); |
| 391 |
| 392 // Loads the list at |path| in the given |hive|. |schema| is a JSON schema |
| 393 // (http://json-schema.org/) that describes the expected type of the list. |
| 394 // Ownership of the result is transferred to the caller. |
| 395 base::ListValue* ReadComponentListValue(HKEY hive, |
| 396 const string16& path, |
| 397 const base::DictionaryValue* schema) { |
| 398 // The sub-elements are indexed from 1 to N. They can be represented as |
| 399 // registry values or registry keys though; use |schema| first to try to |
| 400 // determine the right type, and if that fails default to STRING. |
| 401 |
| 402 RegKey key(hive, path.c_str(), KEY_READ); |
| 403 if (!key.Valid()) |
| 404 return NULL; |
| 405 |
| 406 // Get the schema for list items. |
| 407 schema = GetEntry(schema, kItems); |
| 408 base::Value::Type type = GetType(schema, base::Value::TYPE_STRING); |
| 409 base::ListValue* list = new base::ListValue(); |
| 410 for (int i = 1; ; ++i) { |
| 411 string16 name = base::IntToString16(i); |
| 412 base::Value* value = NULL; |
| 413 if (type == base::Value::TYPE_DICTIONARY) { |
| 414 value = |
| 415 ReadComponentDictionaryValue(hive, path + kPathSep + name, schema); |
| 416 } else if (type == base::Value::TYPE_LIST) { |
| 417 value = ReadComponentListValue(hive, path + kPathSep + name, schema); |
| 418 } else { |
| 419 DWORD reg_type; |
| 420 key.ReadValue(name.c_str(), NULL, NULL, ®_type); |
| 421 value = ReadComponentSimpleValue(&key, name, reg_type, type); |
| 422 } |
| 423 if (!value) |
| 424 break; |
| 425 list->Append(value); |
| 426 } |
| 427 return list; |
| 428 } |
| 429 |
| 430 // Loads the dictionary at |path| in the given |hive|. |schema| is a JSON |
| 431 // schema (http://json-schema.org/) that describes the expected types for the |
| 432 // dictionary entries. When the type for a certain entry isn't described in the |
| 433 // schema, a default conversion takes place. |schema| can be NULL. |
| 434 // Ownership of the result is transferred to the caller. |
| 435 base::DictionaryValue* ReadComponentDictionaryValue( |
| 436 HKEY hive, |
| 437 const string16& path, |
| 438 const base::DictionaryValue* schema) { |
223 // A "value" in the registry is like a file in a filesystem, and a "key" is | 439 // A "value" in the registry is like a file in a filesystem, and a "key" is |
224 // like a directory, that contains other "values" and "keys". | 440 // like a directory, that contains other "values" and "keys". |
225 // Unfortunately it is possible to have a name both as a "value" and a "key". | 441 // Unfortunately it is possible to have a name both as a "value" and a "key". |
226 // In those cases, the sub "key" will be ignored; this choice is arbitrary. | 442 // In those cases, the sub "key" will be ignored; this choice is arbitrary. |
227 | 443 |
228 // First iterate over all the "values" in |path| and convert them; then | 444 // First iterate over all the "values" in |path| and convert them; then |
229 // recurse into each "key" in |path| and convert them as dictionaries. | 445 // recurse into each "key" in |path| and convert them as dictionaries. |
230 | 446 |
| 447 RegKey key(hive, path.c_str(), KEY_READ); |
| 448 if (!key.Valid()) |
| 449 return NULL; |
| 450 |
231 base::DictionaryValue* dict = new base::DictionaryValue(); | 451 base::DictionaryValue* dict = new base::DictionaryValue(); |
232 RegKey key(hive, path.c_str(), KEY_READ); | |
233 | |
234 for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { | 452 for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { |
235 string16 name(it.Name()); | 453 string16 name16(it.Name()); |
236 switch (it.Type()) { | 454 std::string name(UTF16ToUTF8(name16)); |
237 case REG_SZ: { | 455 const base::DictionaryValue* sub_schema = GetSchemaFor(schema, name); |
238 string16 value; | 456 base::Value::Type type = GetType(sub_schema, GetDefaultFor(it.Type())); |
239 if (ReadRegistryString(&key, name, &value)) | 457 base::Value* value = |
240 dict->SetString(UTF16ToUTF8(name), value); | 458 ReadComponentSimpleValue(&key, name16, it.Type(), type); |
241 break; | 459 if (value) |
242 } | 460 dict->Set(name, value); |
243 | |
244 case REG_DWORD: { | |
245 uint32 value; | |
246 if (ReadRegistryInteger(&key, name, &value)) | |
247 dict->SetInteger(UTF16ToUTF8(name), value); | |
248 break; | |
249 } | |
250 | |
251 default: | |
252 // TODO(joaodasilva): use a schema to determine the correct types. | |
253 LOG(WARNING) << "Ignoring registry value with unsupported type: " | |
254 << path << kPathSep << name; | |
255 } | |
256 } | 461 } |
257 | 462 |
258 for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { | 463 for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { |
259 string16 name16(it.Name()); | 464 string16 name16(it.Name()); |
260 std::string name(UTF16ToUTF8(name16)); | 465 std::string name(UTF16ToUTF8(name16)); |
261 if (dict->HasKey(name)) { | 466 if (dict->HasKey(name)) { |
262 LOG(WARNING) << "Ignoring registry key because a value exists with the " | 467 DLOG(WARNING) << "Ignoring registry key because a value exists with the " |
263 "same name: " << path << kPathSep << name; | 468 "same name: " << path << kPathSep << name; |
264 continue; | 469 continue; |
265 } | 470 } |
266 base::DictionaryValue* value = | 471 |
267 ReadRegistryDictionaryValue(hive, path + kPathSep + name16); | 472 base::DictionaryValue* sub_schema = GetSchemaFor(schema, name); |
| 473 base::Value::Type type = GetType(sub_schema, base::Value::TYPE_DICTIONARY); |
| 474 base::Value* value = NULL; |
| 475 const string16 sub_path = path + kPathSep + name16; |
| 476 if (type == base::Value::TYPE_DICTIONARY) { |
| 477 value = ReadComponentDictionaryValue(hive, sub_path, sub_schema); |
| 478 } else if (type == base::Value::TYPE_LIST) { |
| 479 value = ReadComponentListValue(hive, sub_path, sub_schema); |
| 480 } else { |
| 481 DLOG(WARNING) << "Can't read a simple type in registry key at " << path; |
| 482 } |
268 if (value) | 483 if (value) |
269 dict->Set(name, value); | 484 dict->Set(name, value); |
270 } | 485 } |
271 | 486 |
272 return dict; | 487 return dict; |
273 } | 488 } |
274 | 489 |
| 490 // Reads a JSON schema from the given |registry_value|, at the given |
| 491 // |registry_key| in |hive|. |registry_value| must be a string (REG_SZ), and |
| 492 // is decoded as JSON data. Returns NULL on failure. Ownership is transferred |
| 493 // to the caller. |
| 494 base::DictionaryValue* ReadRegistrySchema(HKEY hive, |
| 495 const string16& registry_key, |
| 496 const string16& registry_value) { |
| 497 RegKey key(hive, registry_key.c_str(), KEY_READ); |
| 498 string16 schema; |
| 499 if (!ReadRegistryString(&key, registry_value, &schema)) |
| 500 return NULL; |
| 501 // A JSON schema is represented in JSON too. |
| 502 scoped_ptr<base::Value> value(base::JSONReader::Read(UTF16ToUTF8(schema))); |
| 503 if (!value.get()) |
| 504 return NULL; |
| 505 base::DictionaryValue* dict = NULL; |
| 506 if (!value->GetAsDictionary(&dict)) |
| 507 return NULL; |
| 508 // The top-level entry must be an object, and each of its properties maps |
| 509 // a policy name to its schema. |
| 510 if (GetType(dict, base::Value::TYPE_DICTIONARY) != |
| 511 base::Value::TYPE_DICTIONARY) { |
| 512 DLOG(WARNING) << "schema top-level type isn't \"object\""; |
| 513 return NULL; |
| 514 } |
| 515 value.release(); |
| 516 return dict; |
| 517 } |
| 518 |
275 } // namespace | 519 } // namespace |
276 | 520 |
277 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) | 521 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) |
278 : is_initialized_(false), | 522 : is_initialized_(false), |
279 policy_list_(policy_list), | 523 policy_list_(policy_list), |
280 user_policy_changed_event_(false, false), | 524 user_policy_changed_event_(false, false), |
281 machine_policy_changed_event_(false, false), | 525 machine_policy_changed_event_(false, false), |
282 user_policy_watcher_failed_(false), | 526 user_policy_watcher_failed_(false), |
283 machine_policy_watcher_failed_(false) { | 527 machine_policy_watcher_failed_(false) { |
284 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { | 528 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 560 |
317 const PolicyDefinitionList::Entry* current; | 561 const PolicyDefinitionList::Entry* current; |
318 for (current = policy_list_->begin; current != policy_list_->end; ++current) { | 562 for (current = policy_list_->begin; current != policy_list_->end; ++current) { |
319 const string16 name(ASCIIToUTF16(current->name)); | 563 const string16 name(ASCIIToUTF16(current->name)); |
320 PolicyLevel level = POLICY_LEVEL_MANDATORY; | 564 PolicyLevel level = POLICY_LEVEL_MANDATORY; |
321 PolicyScope scope = POLICY_SCOPE_MACHINE; | 565 PolicyScope scope = POLICY_SCOPE_MACHINE; |
322 base::Value* value = NULL; | 566 base::Value* value = NULL; |
323 | 567 |
324 switch (current->value_type) { | 568 switch (current->value_type) { |
325 case base::Value::TYPE_STRING: | 569 case base::Value::TYPE_STRING: |
326 value = ReadStringValue(name, &level, &scope); | 570 value = ReadChromeStringValue(name, &level, &scope); |
327 break; | 571 break; |
328 | 572 |
329 case base::Value::TYPE_LIST: | 573 case base::Value::TYPE_LIST: |
330 value = ReadStringListValue(name, &level, &scope); | 574 value = ReadChromeStringListValue(name, &level, &scope); |
331 break; | 575 break; |
332 | 576 |
333 case base::Value::TYPE_BOOLEAN: | 577 case base::Value::TYPE_BOOLEAN: |
334 value = ReadBooleanValue(name, &level, &scope); | 578 value = ReadChromeBooleanValue(name, &level, &scope); |
335 break; | 579 break; |
336 | 580 |
337 case base::Value::TYPE_INTEGER: | 581 case base::Value::TYPE_INTEGER: |
338 value = ReadIntegerValue(name, &level, &scope); | 582 value = ReadChromeIntegerValue(name, &level, &scope); |
339 break; | 583 break; |
340 | 584 |
341 case base::Value::TYPE_DICTIONARY: | 585 case base::Value::TYPE_DICTIONARY: |
342 value = ReadDictionaryValue(name, &level, &scope); | 586 value = ReadChromeDictionaryValue(name, &level, &scope); |
343 break; | 587 break; |
344 | 588 |
345 default: | 589 default: |
346 NOTREACHED(); | 590 NOTREACHED(); |
347 } | 591 } |
348 | 592 |
349 if (value) | 593 if (value) |
350 chrome_policies->Set(current->name, level, scope, value); | 594 chrome_policies->Set(current->name, level, scope, value); |
351 } | 595 } |
352 } | 596 } |
(...skipping 14 matching lines...) Expand all Loading... |
367 // order of priority. | 611 // order of priority. |
368 static const struct { | 612 static const struct { |
369 const char* path; | 613 const char* path; |
370 PolicyLevel level; | 614 PolicyLevel level; |
371 } kKeyPaths[] = { | 615 } kKeyPaths[] = { |
372 { "policy", POLICY_LEVEL_MANDATORY }, | 616 { "policy", POLICY_LEVEL_MANDATORY }, |
373 { "recommended", POLICY_LEVEL_RECOMMENDED }, | 617 { "recommended", POLICY_LEVEL_RECOMMENDED }, |
374 }; | 618 }; |
375 | 619 |
376 // Path where policies for components are stored. | 620 // Path where policies for components are stored. |
377 const string16 kPathPrefix = | 621 const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep + |
378 kRegistryMandatorySubKey + ASCIIToUTF16(k3rdPartyPolicySubKey); | 622 kThirdParty + kPathSep; |
379 | 623 |
380 for (size_t h = 0; h < arraysize(kHives); ++h) { | 624 for (size_t h = 0; h < arraysize(kHives); ++h) { |
381 HKEY hkey = kHives[h].hive; | 625 HKEY hkey = kHives[h].hive; |
382 | 626 |
383 for (size_t d = 0; d < arraysize(kDomains); ++d) { | 627 for (size_t d = 0; d < arraysize(kDomains); ++d) { |
384 // Each subkey under this domain is a component of that domain. | 628 // Each subkey under this domain is a component of that domain. |
385 // |domain_path| == SOFTWARE\Policies\Chromium\3rdparty\<domain> | 629 // |domain_path| == SOFTWARE\Policies\Chromium\3rdparty\<domain> |
386 string16 domain_path = kPathPrefix + ASCIIToUTF16(kDomains[d].name); | 630 string16 domain_path = kPathPrefix + ASCIIToUTF16(kDomains[d].name); |
387 | 631 |
388 for (RegistryKeyIterator domain_iterator(hkey, domain_path.c_str()); | 632 for (RegistryKeyIterator domain_iterator(hkey, domain_path.c_str()); |
389 domain_iterator.Valid(); ++domain_iterator) { | 633 domain_iterator.Valid(); ++domain_iterator) { |
390 string16 component(domain_iterator.Name()); | 634 string16 component(domain_iterator.Name()); |
391 string16 component_path = domain_path + kPathSep + component; | 635 string16 component_path = domain_path + kPathSep + component; |
392 | 636 |
| 637 // Load the schema for this component's policy, if present. |
| 638 scoped_ptr<base::DictionaryValue> schema( |
| 639 ReadRegistrySchema(hkey, component_path, kSchema)); |
| 640 |
393 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { | 641 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { |
394 string16 path = | 642 string16 path = |
395 component_path + kPathSep + ASCIIToUTF16(kKeyPaths[k].path); | 643 component_path + kPathSep + ASCIIToUTF16(kKeyPaths[k].path); |
396 | 644 |
397 scoped_ptr<base::DictionaryValue> dictionary( | 645 scoped_ptr<base::DictionaryValue> dictionary( |
398 ReadRegistryDictionaryValue(hkey, path)); | 646 ReadComponentDictionaryValue(hkey, path, schema.get())); |
399 if (dictionary.get()) { | 647 if (dictionary.get()) { |
400 PolicyMap policies; | 648 PolicyMap policies; |
401 policies.LoadFrom( | 649 policies.LoadFrom( |
402 dictionary.get(), kKeyPaths[k].level, kHives[h].scope); | 650 dictionary.get(), kKeyPaths[k].level, kHives[h].scope); |
403 // LoadFrom() overwrites any existing values. Use a temporary map | 651 // LoadFrom() overwrites any existing values. Use a temporary map |
404 // and then use MergeFrom(), that only overwrites values with lower | 652 // and then use MergeFrom(), that only overwrites values with lower |
405 // priority. | 653 // priority. |
406 bundle->Get(kDomains[d].domain, UTF16ToUTF8(component)) | 654 bundle->Get(kDomains[d].domain, UTF16ToUTF8(component)) |
407 .MergeFrom(policies); | 655 .MergeFrom(policies); |
408 } | 656 } |
(...skipping 23 matching lines...) Expand all Loading... |
432 | 680 |
433 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { | 681 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { |
434 DCHECK(object == user_policy_changed_event_.handle() || | 682 DCHECK(object == user_policy_changed_event_.handle() || |
435 object == machine_policy_changed_event_.handle()) | 683 object == machine_policy_changed_event_.handle()) |
436 << "unexpected object signaled policy reload, obj = " | 684 << "unexpected object signaled policy reload, obj = " |
437 << std::showbase << std::hex << object; | 685 << std::showbase << std::hex << object; |
438 Reload(false); | 686 Reload(false); |
439 } | 687 } |
440 | 688 |
441 } // namespace policy | 689 } // namespace policy |
OLD | NEW |