Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: chrome/browser/policy/policy_loader_win.cc

Issue 10656046: Use a schema to decode 3rd party policy on windows, when present. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Addressed comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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, &reg_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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/policy/policy_loader_win.h ('k') | chrome/browser/policy/policy_loader_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698