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