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

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

Issue 13619014: Change PolicyLoaderWin to load PReg files if possible. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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 | Annotate | Revision Log
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
11 #include <rpc.h> // For struct GUID
12 #include <shlwapi.h> // For PathIsUNC()
11 #include <userenv.h> 13 #include <userenv.h>
12 14
13 // userenv.dll is required for RegisterGPNotification(). 15 // userenv.dll is required for RegisterGPNotification() and GetAppliedGPOList().
14 #pragma comment(lib, "userenv.lib") 16 #pragma comment(lib, "userenv.lib")
17 // shlwapi.dll is required for PathIsUNC().
18 #pragma comment(lib, "shlwapi.lib")
Joao da Silva 2013/04/05 13:55:01 nit: order
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
15 19
16 #include "base/basictypes.h" 20 #include "base/basictypes.h"
21 #include "base/files/file_path.h"
17 #include "base/json/json_reader.h" 22 #include "base/json/json_reader.h"
18 #include "base/logging.h" 23 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/string16.h" 24 #include "base/string16.h"
25 #include "base/string_util.h"
21 #include "base/strings/string_number_conversions.h" 26 #include "base/strings/string_number_conversions.h"
27 #include "base/sys_byteorder.h"
22 #include "base/utf_string_conversions.h" 28 #include "base/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "base/win/registry.h" 29 #include "base/win/registry.h"
25 #include "chrome/browser/policy/policy_bundle.h" 30 #include "chrome/browser/policy/policy_bundle.h"
26 #include "chrome/browser/policy/policy_map.h" 31 #include "chrome/browser/policy/policy_map.h"
32 #include "chrome/browser/policy/preg_parser_win.h"
27 #include "chrome/common/json_schema/json_schema_constants.h" 33 #include "chrome/common/json_schema/json_schema_constants.h"
28 #include "policy/policy_constants.h" 34 #include "policy/policy_constants.h"
29 35
30 namespace schema = json_schema_constants; 36 namespace schema = json_schema_constants;
31 37
32 using base::win::RegKey; 38 using base::win::RegKey;
33 using base::win::RegistryKeyIterator; 39 using base::win::RegistryKeyIterator;
34 using base::win::RegistryValueIterator; 40 using base::win::RegistryValueIterator;
35 using namespace policy::registry_constants; 41 using namespace policy::registry_constants;
36 42
37 namespace policy { 43 namespace policy {
38 44
39 namespace registry_constants { 45 namespace registry_constants {
40 const wchar_t kPathSep[] = L"\\"; 46 const wchar_t kPathSep[] = L"\\";
41 const wchar_t kThirdParty[] = L"3rdparty"; 47 const wchar_t kThirdParty[] = L"3rdparty";
42 const wchar_t kMandatory[] = L"policy"; 48 const wchar_t kMandatory[] = L"policy";
43 const wchar_t kRecommended[] = L"recommended"; 49 const wchar_t kRecommended[] = L"recommended";
44 const wchar_t kSchema[] = L"schema"; 50 const wchar_t kSchema[] = L"schema";
45 } // namespace registry_constants 51 } // namespace registry_constants
46 52
47 namespace { 53 namespace {
48 54
49 // Map of registry hives to their corresponding policy scope, in decreasing 55 const char kKeyMandatory[] = "policy";
50 // order of priority. 56 const char kKeyRecommended[] = "recommended";
51 const struct { 57 const char kKeySchema[] = "schema";
52 HKEY hive; 58 const char kKeyThirdParty[] = "3rdparty";
53 PolicyScope scope; 59
54 } kHives[] = { 60 // The GUID of the registry settings group policy extension.
55 { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, 61 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID;
56 { HKEY_CURRENT_USER, POLICY_SCOPE_USER }, 62
63 // The PReg file name.
64 const base::FilePath::CharType kPRegFileName[] =
65 FILE_PATH_LITERAL("Registry.pol");
66
67 // Deleter for using GPO lists with scoped_ptr.
68 struct FreeGPOListDeleter {
69 inline void operator()(GROUP_POLICY_OBJECT* ptr) const {
70 FreeGPOList(ptr);
71 }
57 }; 72 };
58 73
59 // Reads a REG_SZ string at |key| named |name| into |result|. Returns false if 74 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL.
60 // the string could not be read. 75 const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary,
61 bool ReadRegistryString(RegKey* key, 76 const std::string& name) {
62 const string16& name, 77 if (!dictionary)
63 string16* result) { 78 return NULL;
64 DWORD value_size = 0; 79 const base::DictionaryValue* entry = NULL;
65 DWORD key_type = 0; 80 dictionary->GetDictionaryWithoutPathExpansion(name, &entry);
66 scoped_array<uint8> buffer; 81 return entry;
67
68 if (key->ReadValue(name.c_str(), 0, &value_size, &key_type) != ERROR_SUCCESS)
69 return false;
70 if (key_type != REG_SZ)
71 return false;
72
73 // According to the Microsoft documentation, the string
74 // buffer may not be explicitly 0-terminated. Allocate a
75 // slightly larger buffer and pre-fill to zeros to guarantee
76 // the 0-termination.
77 buffer.reset(new uint8[value_size + 2]);
78 memset(buffer.get(), 0, value_size + 2);
79 key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
80 result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
81 return true;
82 } 82 }
83 83
84 // Reads a REG_DWORD integer at |key| named |name| into |result|. Returns false 84 // Tries to extract the dictionary at |key| in |dict| and returns it.
85 // if the value could no be read. 85 scoped_ptr<base::DictionaryValue> RemoveDict(base::DictionaryValue* dict,
86 bool ReadRegistryInteger(RegKey* key, 86 const std::string& key) {
87 const string16& name, 87 base::Value* entry = NULL;
88 uint32* result) { 88 base::DictionaryValue* result_dict = NULL;
89 DWORD dword; 89 if (dict && dict->RemoveWithoutPathExpansion(key, &entry) && entry)
90 if (key->ReadValueDW(name.c_str(), &dword) != ERROR_SUCCESS) 90 entry->GetAsDictionary(&result_dict);
Joao da Silva 2013/04/05 13:55:01 This leaks |entry| if it's not a dictionary.
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
91 return false; 91
92 *result = dword; 92 return make_scoped_ptr(result_dict);
93 return true; 93 }
94
95 std::string GetSchemaTypeForValueType(base::Value::Type value_type) {
96 switch (value_type) {
97 case base::Value::TYPE_DICTIONARY:
98 return json_schema_constants::kObject;
99 case base::Value::TYPE_INTEGER:
100 return json_schema_constants::kInteger;
101 case base::Value::TYPE_LIST:
102 return json_schema_constants::kArray;
103 case base::Value::TYPE_BOOLEAN:
104 return json_schema_constants::kBoolean;
105 case base::Value::TYPE_STRING:
106 return json_schema_constants::kString;
107 default:
108 break;
109 }
110
111 NOTREACHED() << "Unsupported policy value type " << value_type;
112 return json_schema_constants::kNull;
94 } 113 }
95 114
96 // Returns the Value type described in |schema|, or |default_type| if not found. 115 // Returns the Value type described in |schema|, or |default_type| if not found.
97 base::Value::Type GetType(const base::DictionaryValue* schema, 116 base::Value::Type GetValueTypeForSchema(const base::DictionaryValue* schema,
98 base::Value::Type default_type) { 117 base::Value::Type default_type) {
99 // JSON-schema types to base::Value::Type mapping. 118 // JSON-schema types to base::Value::Type mapping.
100 static const struct { 119 static const struct {
101 // JSON schema type. 120 // JSON schema type.
102 const char* schema_type; 121 const char* schema_type;
103 // Correspondent value type. 122 // Correspondent value type.
104 base::Value::Type value_type; 123 base::Value::Type value_type;
105 } kSchemaToValueTypeMap[] = { 124 } kSchemaToValueTypeMap[] = {
106 { schema::kArray, base::Value::TYPE_LIST }, 125 { schema::kArray, base::Value::TYPE_LIST },
107 { schema::kBoolean, base::Value::TYPE_BOOLEAN }, 126 { schema::kBoolean, base::Value::TYPE_BOOLEAN },
108 { schema::kInteger, base::Value::TYPE_INTEGER }, 127 { schema::kInteger, base::Value::TYPE_INTEGER },
109 { schema::kNull, base::Value::TYPE_NULL }, 128 { schema::kNull, base::Value::TYPE_NULL },
110 { schema::kNumber, base::Value::TYPE_DOUBLE }, 129 { schema::kNumber, base::Value::TYPE_DOUBLE },
111 { schema::kObject, base::Value::TYPE_DICTIONARY }, 130 { schema::kObject, base::Value::TYPE_DICTIONARY },
112 { schema::kString, base::Value::TYPE_STRING }, 131 { schema::kString, base::Value::TYPE_STRING },
113 }; 132 };
114 133
115 if (!schema) 134 if (!schema)
116 return default_type; 135 return default_type;
117 std::string type; 136 std::string type;
118 if (!schema->GetString(schema::kType, &type)) 137 if (!schema->GetStringWithoutPathExpansion(schema::kType, &type))
119 return default_type; 138 return default_type;
120 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { 139 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) {
121 if (type == kSchemaToValueTypeMap[i].schema_type) 140 if (type == kSchemaToValueTypeMap[i].schema_type)
122 return kSchemaToValueTypeMap[i].value_type; 141 return kSchemaToValueTypeMap[i].value_type;
123 } 142 }
124 return default_type; 143 return default_type;
125 } 144 }
126 145
127 // Returns the default type for registry entries of |reg_type|, when there is
128 // no schema defined type for a policy.
129 base::Value::Type GetDefaultFor(DWORD reg_type) {
130 return reg_type == REG_DWORD ? base::Value::TYPE_INTEGER :
131 base::Value::TYPE_STRING;
132 }
133
134 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL.
135 const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary,
136 const std::string& name) {
137 if (!dictionary)
138 return NULL;
139 const base::DictionaryValue* entry = NULL;
140 dictionary->GetDictionary(name, &entry);
141 return entry;
142 }
143
144 // Returns the schema for property |name| given the |schema| of an object. 146 // Returns the schema for property |name| given the |schema| of an object.
145 // Returns the "additionalProperties" schema if no specific schema for 147 // Returns the "additionalProperties" schema if no specific schema for
146 // |name| is present. Returns NULL if no schema is found. 148 // |name| is present. Returns NULL if no schema is found.
147 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, 149 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema,
148 const std::string& name) { 150 const std::string& name) {
149 const base::DictionaryValue* properties = 151 const base::DictionaryValue* properties =
150 GetEntry(schema, schema::kProperties); 152 GetEntry(schema, schema::kProperties);
151 const base::DictionaryValue* sub_schema = GetEntry(properties, name); 153 const base::DictionaryValue* sub_schema = GetEntry(properties, name);
152 if (sub_schema) 154 if (sub_schema)
153 return sub_schema; 155 return sub_schema;
154 // "additionalProperties" can be a boolean, but that case is ignored. 156 // "additionalProperties" can be a boolean, but that case is ignored.
155 return GetEntry(schema, schema::kAdditionalProperties); 157 return GetEntry(schema, schema::kAdditionalProperties);
156 } 158 }
157 159
158 // Converts string |value| to another |type|, if possible. 160 // Reads the subtree of the Windows registry at |root| into the passed |dict|.
159 base::Value* ConvertStringValue(const string16& value, base::Value::Type type) { 161 void ReadRegistry(HKEY hive,
160 switch (type) { 162 const std::wstring& root,
161 case base::Value::TYPE_NULL: 163 base::DictionaryValue* dict) {
162 return base::Value::CreateNullValue(); 164 // Open the key.
163 165 RegKey key(hive, root.c_str(), KEY_READ);
166 if (!key.Valid())
167 return;
168
169 // First, read all the values of the key.
170 for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) {
171 const std::string name = UTF16ToUTF8(it.Name());
172 DWORD type;
173 if (key.ReadValue(it.Name(), NULL, 0, &type) == ERROR_SUCCESS) {
174 switch (type) {
175 case REG_SZ:
176 case REG_EXPAND_SZ: {
177 std::wstring wstring_value;
178 if (key.ReadValue(it.Name(), &wstring_value) == ERROR_SUCCESS) {
Joao da Silva 2013/04/05 13:55:01 ReadValue() internally limits the value size to 10
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Good point. Instead of reviving ReadRegistryString
179 dict->SetStringWithoutPathExpansion(name,
180 UTF16ToUTF8(wstring_value));
181 continue;
182 }
183 break;
184 }
185 case REG_DWORD_LITTLE_ENDIAN:
186 case REG_DWORD_BIG_ENDIAN: {
187 DWORD dword_value = 0;
188 if (key.ReadValueDW(it.Name(), &dword_value) == ERROR_SUCCESS) {
189 if (type == REG_DWORD_BIG_ENDIAN)
190 dword_value = base::NetToHost32(dword_value);
191 else
192 dword_value = base::ByteSwapToLE32(dword_value);
193 dict->SetIntegerWithoutPathExpansion(name, dword_value);
194 continue;
195 }
196 break;
197 }
198 case REG_NONE:
199 case REG_LINK:
200 case REG_MULTI_SZ:
201 case REG_RESOURCE_LIST:
202 case REG_FULL_RESOURCE_DESCRIPTOR:
203 case REG_RESOURCE_REQUIREMENTS_LIST:
204 case REG_QWORD_LITTLE_ENDIAN:
205 // Unsupported type, message gets logged below.
206 break;
207 }
208 }
209
210 LOG(WARNING) << "Failed to read hive " << hive << " at "
211 << root << kPathSep << name
212 << " type " << type;
213 }
214
215 // Recurse for all subkeys.
216 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) {
217 std::string name(UTF16ToUTF8(it.Name()));
218 if (dict->HasKey(name)) {
219 DLOG(WARNING) << "Ignoring registry key because a value exists with the "
220 "same name: " << root << kPathSep << name;
221 } else {
222 scoped_ptr<base::DictionaryValue> subdict(new base::DictionaryValue());
223 ReadRegistry(hive, root + kPathSep + it.Name(), subdict.get());
224 dict->SetWithoutPathExpansion(name, subdict.release());
225 }
226 }
227 }
228
229 // Converts |value| in raw GPO representation to the internal policy value, as
230 // described by |schema|. This maps the ambiguous GPO data types to the
231 // internal policy value representations.
232 scoped_ptr<base::Value> ConvertPolicyValue(
233 const base::Value& value,
234 const base::DictionaryValue* schema) {
235 // Figure out the type to convert to from the schema.
236 const base::Value::Type result_type(
237 GetValueTypeForSchema(schema, value.GetType()));
238
239 // If the type is good already, go with it.
240 if (value.IsType(result_type)) {
241 // Recurse for complex types if there is a schema.
242 if (schema) {
243 const base::DictionaryValue* dict = NULL;
244 const base::ListValue* list = NULL;
245 if (value.GetAsDictionary(&dict)) {
246 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
247 for (base::DictionaryValue::Iterator entry(*dict); entry.HasNext();
248 entry.Advance()) {
249 scoped_ptr<base::Value> converted_value(
250 ConvertPolicyValue(entry.value(),
251 GetSchemaFor(schema, entry.key())));
252 result->Set(entry.key(), converted_value.release());
253 }
254 return result.Pass();
255 } else if (value.GetAsList(&list)) {
256 scoped_ptr<base::ListValue> result(new base::ListValue());
257 for (base::ListValue::const_iterator entry(list->begin());
258 entry != list->end(); ++entry) {
259 scoped_ptr<base::Value> converted_value(
260 ConvertPolicyValue(**entry, GetEntry(schema, schema::kItems)));
Joao da Silva 2013/04/05 13:55:01 The GetEntry() call can be outside the loop
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
261 result->Append(converted_value.release());
262 }
263 return result.Pass();
264 }
265 }
266 return make_scoped_ptr(value.DeepCopy());
267 }
268
269 // Else, do some conversions to map windows registry data types to JSON types.
270 std::string string_value;
271 int int_value = 0;
272 switch (result_type) {
273 case base::Value::TYPE_NULL: {
274 return make_scoped_ptr(base::Value::CreateNullValue());
275 }
164 case base::Value::TYPE_BOOLEAN: { 276 case base::Value::TYPE_BOOLEAN: {
165 int int_value; 277 // Accept booleans encoded as either string or integer.
166 if (base::StringToInt(value, &int_value)) 278 if (value.GetAsInteger(&int_value) ||
167 return base::Value::CreateBooleanValue(int_value != 0); 279 (value.GetAsString(&string_value) &&
168 return NULL; 280 base::StringToInt(string_value, &int_value))) {
169 } 281 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0));
170 282 }
283 break;
284 }
171 case base::Value::TYPE_INTEGER: { 285 case base::Value::TYPE_INTEGER: {
172 int int_value; 286 // Integers may be string-encoded.
173 if (base::StringToInt(value, &int_value)) 287 if (value.GetAsString(&string_value) &&
174 return base::Value::CreateIntegerValue(int_value); 288 base::StringToInt(string_value, &int_value)) {
175 return NULL; 289 return make_scoped_ptr(base::Value::CreateIntegerValue(int_value));
176 } 290 }
177 291 break;
292 }
178 case base::Value::TYPE_DOUBLE: { 293 case base::Value::TYPE_DOUBLE: {
179 double double_value; 294 // Doubles may be string-encoded or integer-encoded.
180 if (base::StringToDouble(UTF16ToUTF8(value), &double_value)) 295 double double_value = 0;
181 return base::Value::CreateDoubleValue(double_value); 296 if (value.GetAsInteger(&int_value)) {
182 DLOG(WARNING) << "Failed to read policy value as double: " << value; 297 return make_scoped_ptr(base::Value::CreateDoubleValue(int_value));
183 return NULL; 298 } else if (value.GetAsString(&string_value) &&
184 } 299 base::StringToDouble(string_value, &double_value)) {
185 300 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value));
186 case base::Value::TYPE_STRING: 301 }
187 return base::Value::CreateStringValue(value); 302 break;
188 303 }
189 case base::Value::TYPE_DICTIONARY: 304 case base::Value::TYPE_LIST: {
190 case base::Value::TYPE_LIST: 305 // Lists are encoded as subkeys with numbered value in the registry.
191 return base::JSONReader::Read(UTF16ToUTF8(value)); 306 const base::DictionaryValue* dict = NULL;
192 307 if (value.GetAsDictionary(&dict)) {
193 case base::Value::TYPE_BINARY: 308 scoped_ptr<base::ListValue> result(new base::ListValue());
194 DLOG(WARNING) << "Cannot convert REG_SZ entry to type " << type; 309 for (int i = 1; ; ++i) {
195 return NULL; 310 const base::Value* entry = NULL;
196 } 311 if (!dict->Get(base::IntToString(i), &entry))
197 NOTREACHED(); 312 break;
198 return NULL; 313 scoped_ptr<base::Value> converted_value(
199 } 314 ConvertPolicyValue(*entry, GetEntry(schema, schema::kItems)));
Joao da Silva 2013/04/05 13:55:01 GetEntry() can be outside the loop
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
200 315 result->Append(converted_value.release());
201 // Converts an integer |value| to another |type|, if possible. 316 }
202 base::Value* ConvertIntegerValue(uint32 value, base::Value::Type type) { 317 return result.Pass();
203 switch (type) { 318 }
204 case base::Value::TYPE_BOOLEAN: 319 // Fall through in order to accept lists encoded as JSON strings.
205 return base::Value::CreateBooleanValue(value != 0); 320 }
206 321 case base::Value::TYPE_DICTIONARY: {
207 case base::Value::TYPE_INTEGER: 322 // Dictionaries may be encoded as JSON strings.
208 return base::Value::CreateIntegerValue(value); 323 if (value.GetAsString(&string_value)) {
209 324 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value));
210 case base::Value::TYPE_DOUBLE: 325 if (result && result->IsType(result_type))
211 return base::Value::CreateDoubleValue(value); 326 return result.Pass();
212 327 }
213 case base::Value::TYPE_NULL: 328 break;
329 }
214 case base::Value::TYPE_STRING: 330 case base::Value::TYPE_STRING:
215 case base::Value::TYPE_BINARY: 331 case base::Value::TYPE_BINARY:
216 case base::Value::TYPE_DICTIONARY: 332 // No conversion possible.
217 case base::Value::TYPE_LIST: 333 break;
218 DLOG(WARNING) << "Cannot convert REG_DWORD entry to type " << type; 334 }
219 return NULL; 335
220 } 336 LOG(WARNING) << "Failed to convert " << value.GetType()
221 NOTREACHED(); 337 << " to " << result_type;
Joao da Silva 2013/04/05 13:55:01 nit: indent
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
222 return NULL; 338 return make_scoped_ptr(base::Value::CreateNullValue());
223 } 339 }
224 340
225 // Reads a value from the registry |key| named |name| with registry type 341 // Parses |gpo_dict| according to |schema| and writes the resulting policy
226 // |registry_type| as a value of type |type|. 342 // settings to |policy| for the given |scope| and |level|.
227 // Returns NULL if the value could not be loaded or converted. 343 void ParsePolicy(const base::DictionaryValue* gpo_dict,
228 base::Value* ReadPolicyValue(RegKey* key, 344 PolicyLevel level,
229 const string16& name, 345 PolicyScope scope,
230 DWORD registry_type, 346 const base::DictionaryValue* schema,
231 base::Value::Type type) { 347 PolicyMap* policy) {
232 switch (registry_type) { 348 if (!gpo_dict)
233 case REG_SZ: { 349 return;
234 string16 value; 350
235 if (ReadRegistryString(key, name, &value)) 351 scoped_ptr<base::Value> policy_value(ConvertPolicyValue(*gpo_dict, schema));
236 return ConvertStringValue(value, type); 352 const base::DictionaryValue* policy_dict = NULL;
237 break; 353 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) {
238 } 354 LOG(WARNING) << "Root policy object is not a dictionary!";
239 355 return;
240 case REG_DWORD: { 356 }
241 uint32 value; 357
242 if (ReadRegistryInteger(key, name, &value)) 358 for (base::DictionaryValue::Iterator it(*policy_dict); it.HasNext();
243 return ConvertIntegerValue(value, type); 359 it.Advance()) {
244 break; 360 policy->Set(it.key(), level, scope, it.value().DeepCopy());
245 } 361 }
Joao da Silva 2013/04/05 13:55:01 policy->LoadFrom(policy_dict, level, scope)
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
246 362 }
247 default: 363
248 DLOG(WARNING) << "Registry type not supported for key " << name; 364 // Queries Windows for applied group policy and write the result to |policy|.
249 break; 365 // This is the preferred way to obtain GPO data, there are reports of abuse
250 } 366 // of the registry GPO keys by 3rd-party software.
251 return NULL; 367 bool ReadPolicyFromGPO(PolicyScope scope, base::DictionaryValue* policy) {
252 } 368 PGROUP_POLICY_OBJECT policy_object_list_pointer = NULL;
253 369 DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0;
254 // Forward declaration for ReadComponentListValue(). 370 if (GetAppliedGPOList(flags, NULL, NULL, &kRegistrySettingsCSEGUID,
255 base::DictionaryValue* ReadComponentDictionaryValue( 371 &policy_object_list_pointer)) {
256 HKEY hive, 372 PLOG(ERROR) << "GetAppliedGPOList for scope " << scope << " failed";
257 const string16& path, 373 return false;
Joao da Silva 2013/04/05 13:55:01 What happens in a machine without any policy? Does
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Yes, I saw that happening in a pristine VM.
258 const base::DictionaryValue* schema); 374 }
259 375 scoped_ptr<GROUP_POLICY_OBJECT, FreeGPOListDeleter> policy_object_list(
260 // Loads the list at |path| in the given |hive|. |schema| is a JSON schema 376 policy_object_list_pointer);
261 // (http://json-schema.org/) that describes the expected type of the list. 377
262 // Ownership of the result is transferred to the caller. 378 base::DictionaryValue regular_policy;
263 base::ListValue* ReadComponentListValue(HKEY hive, 379 base::DictionaryValue forced_policy;
264 const string16& path, 380 for (GROUP_POLICY_OBJECT* policy_object = policy_object_list.get();
265 const base::DictionaryValue* schema) { 381 policy_object; policy_object = policy_object->pNext) {
266 // The sub-elements are indexed from 1 to N. They can be represented as 382 /*
267 // registry values or registry keys though; use |schema| first to try to 383 LOG(ERROR) << "GPO object: " << std::endl
268 // determine the right type, and if that fails default to STRING. 384 << "options " << policy_object->dwOptions << std::endl
269 385 << "version " << policy_object->dwVersion << std::endl
270 RegKey key(hive, path.c_str(), KEY_READ); 386 << "dspath " << policy_object->lpDSPath << std::endl
271 if (!key.Valid()) 387 << "lpFileSysPath " << policy_object->lpFileSysPath << std::endl
272 return NULL; 388 << "lpDisplayName " << policy_object->lpDisplayName << std::endl
273 389 << "GPOName " << policy_object->szGPOName << std::endl
274 // Get the schema for list items. 390 << "GPOLink " << policy_object->GPOLink << std::endl
275 schema = GetEntry(schema, schema::kItems); 391 << "lParam " << policy_object->lParam << std::endl
276 base::Value::Type type = GetType(schema, base::Value::TYPE_STRING); 392 << "next " << policy_object->pNext << std::endl
277 base::ListValue* list = new base::ListValue(); 393 << "prev " << policy_object->pPrev << std::endl
278 for (int i = 1; ; ++i) { 394 << "lpExtensions " << policy_object->lpExtensions << std::endl
279 string16 name = base::IntToString16(i); 395 << "lParam2 " << policy_object->lParam2 << std::endl
280 base::Value* value = NULL; 396 << "lpLink " << policy_object->lpLink << std::endl;
Joao da Silva 2013/04/05 13:55:01 You've been having some fun eh :-)
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
281 if (type == base::Value::TYPE_DICTIONARY) { 397 */
282 value = 398
283 ReadComponentDictionaryValue(hive, path + kPathSep + name, schema); 399 if (policy_object->dwOptions & GPO_FLAG_DISABLE)
Joao da Silva 2013/04/05 13:55:01 It's not clear to me if this flag is set for boole
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 This refers to the entire GroupPolicyObject, not i
284 } else if (type == base::Value::TYPE_LIST) { 400 continue;
285 value = ReadComponentListValue(hive, path + kPathSep + name, schema); 401
402 if (PathIsUNC(policy_object->lpFileSysPath)) {
Joao da Silva 2013/04/05 13:55:01 Can policy_object->lpDSPath have more policy that
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 I've actually looked at the DS portion, there's on
403 // UNC path: Assume this is an AD-managed machine, which updates the
404 // registry via GPO's standard registry CSE periodically. Fall back to
405 // reading from the registry in this case.
406 return false;
407 }
408
409 base::FilePath preg_file_path(
410 base::FilePath(policy_object->lpFileSysPath).Append(kPRegFileName));
411 if (policy_object->dwOptions & GPO_FLAG_FORCE) {
412 base::DictionaryValue new_forced_policy;
413 if (!preg_parser::ReadFile(preg_file_path, &new_forced_policy))
Joao da Silva 2013/04/05 13:55:01 This is going to read all the policies for all the
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 I had done that already, but not updated the uploa
414 return false;
415
416 // Merge with existing forced policy, giving precedence to the existing
417 // forced policy.
418 new_forced_policy.MergeDictionary(&forced_policy);
419 forced_policy.Swap(&new_forced_policy);
286 } else { 420 } else {
287 DWORD reg_type; 421 if (!preg_parser::ReadFile(preg_file_path, &regular_policy))
288 key.ReadValue(name.c_str(), NULL, NULL, &reg_type); 422 return false;
289 if (reg_type != REG_NONE) 423 }
290 value = ReadPolicyValue(&key, name, reg_type, type); 424 }
291 } 425
292 if (value) 426 // Construct the resulting policy data dictionary.
293 list->Append(value); 427 base::DictionaryValue gpo_policy;
294 else 428 gpo_policy.MergeDictionary(&regular_policy);
Joao da Silva 2013/04/05 13:55:01 Swap?
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 Done.
295 break; 429 gpo_policy.MergeDictionary(&forced_policy);
296 } 430
297 return list; 431 // Extract the Chrome-specific part.
298 } 432 std::string path;
299 433 ReplaceChars(UTF16ToUTF8(kRegistryChromePolicyKey), "\\", ".", &path);
300 // Loads the dictionary at |path| in the given |hive|. |schema| is a JSON 434 base::DictionaryValue* chrome_policy;
301 // schema (http://json-schema.org/) that describes the expected types for the 435 if (gpo_policy.GetDictionary(path, &chrome_policy))
302 // dictionary entries. When the type for a certain entry isn't described in the 436 policy->Swap(chrome_policy);
303 // schema, a default conversion takes place. |schema| can be NULL. 437
304 // Ownership of the result is transferred to the caller. 438 return true;
305 base::DictionaryValue* ReadComponentDictionaryValue(
306 HKEY hive,
307 const string16& path,
308 const base::DictionaryValue* schema) {
309 // A "value" in the registry is like a file in a filesystem, and a "key" is
310 // like a directory, that contains other "values" and "keys".
311 // Unfortunately it is possible to have a name both as a "value" and a "key".
312 // In those cases, the sub "key" will be ignored; this choice is arbitrary.
313
314 // First iterate over all the "values" in |path| and convert them; then
315 // recurse into each "key" in |path| and convert them as dictionaries.
316
317 RegKey key(hive, path.c_str(), KEY_READ);
318 if (!key.Valid())
319 return NULL;
320
321 base::DictionaryValue* dict = new base::DictionaryValue();
322 for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) {
323 string16 name16(it.Name());
324 std::string name(UTF16ToUTF8(name16));
325 const base::DictionaryValue* sub_schema = GetSchemaFor(schema, name);
326 base::Value::Type type = GetType(sub_schema, GetDefaultFor(it.Type()));
327 base::Value* value = ReadPolicyValue(&key, name16, it.Type(), type);
328 if (value)
329 dict->Set(name, value);
330 }
331
332 for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) {
333 string16 name16(it.Name());
334 std::string name(UTF16ToUTF8(name16));
335 if (dict->HasKey(name)) {
336 DLOG(WARNING) << "Ignoring registry key because a value exists with the "
337 "same name: " << path << kPathSep << name;
338 continue;
339 }
340
341 const base::DictionaryValue* sub_schema = GetSchemaFor(schema, name);
342 base::Value::Type type = GetType(sub_schema, base::Value::TYPE_DICTIONARY);
343 base::Value* value = NULL;
344 const string16 sub_path = path + kPathSep + name16;
345 if (type == base::Value::TYPE_DICTIONARY) {
346 value = ReadComponentDictionaryValue(hive, sub_path, sub_schema);
347 } else if (type == base::Value::TYPE_LIST) {
348 value = ReadComponentListValue(hive, sub_path, sub_schema);
349 } else {
350 DLOG(WARNING) << "Can't read a simple type in registry key at " << path;
351 }
352 if (value)
353 dict->Set(name, value);
354 }
355
356 return dict;
357 }
358
359 // Reads a JSON schema from the given |registry_value|, at the given
360 // |registry_key| in |hive|. |registry_value| must be a string (REG_SZ), and
361 // is decoded as JSON data. Returns NULL on failure. Ownership is transferred
362 // to the caller.
363 base::DictionaryValue* ReadRegistrySchema(HKEY hive,
364 const string16& registry_key,
365 const string16& registry_value) {
366 RegKey key(hive, registry_key.c_str(), KEY_READ);
367 string16 schema;
368 if (!ReadRegistryString(&key, registry_value, &schema))
369 return NULL;
370 // A JSON schema is represented in JSON too.
371 scoped_ptr<base::Value> value(base::JSONReader::Read(UTF16ToUTF8(schema)));
372 if (!value.get())
373 return NULL;
374 base::DictionaryValue* dict = NULL;
375 if (!value->GetAsDictionary(&dict))
376 return NULL;
377 // The top-level entry must be an object, and each of its properties maps
378 // a policy name to its schema.
379 if (GetType(dict, base::Value::TYPE_DICTIONARY) !=
380 base::Value::TYPE_DICTIONARY) {
381 DLOG(WARNING) << "schema top-level type isn't \"object\"";
382 return NULL;
383 }
384 value.release();
385 return dict;
386 } 439 }
387 440
388 } // namespace 441 } // namespace
389 442
390 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) 443 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list)
391 : is_initialized_(false), 444 : is_initialized_(false),
392 policy_list_(policy_list), 445 policy_list_(policy_list),
393 user_policy_changed_event_(false, false), 446 user_policy_changed_event_(false, false),
394 machine_policy_changed_event_(false, false), 447 machine_policy_changed_event_(false, false),
395 user_policy_watcher_failed_(false), 448 user_policy_watcher_failed_(false),
396 machine_policy_watcher_failed_(false) { 449 machine_policy_watcher_failed_(false) {
397 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { 450 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
398 DPLOG(WARNING) << "Failed to register user group policy notification"; 451 DPLOG(WARNING) << "Failed to register user group policy notification";
399 user_policy_watcher_failed_ = true; 452 user_policy_watcher_failed_ = true;
400 } 453 }
401 if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { 454 if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
402 DPLOG(WARNING) << "Failed to register machine group policy notification."; 455 DPLOG(WARNING) << "Failed to register machine group policy notification.";
403 machine_policy_watcher_failed_ = true; 456 machine_policy_watcher_failed_ = true;
404 } 457 }
405 } 458 }
406 459
407 PolicyLoaderWin::~PolicyLoaderWin() { 460 PolicyLoaderWin::~PolicyLoaderWin() {
408 user_policy_watcher_.StopWatching(); 461 user_policy_watcher_.StopWatching();
409 machine_policy_watcher_.StopWatching(); 462 machine_policy_watcher_.StopWatching();
410 } 463 }
411 464
412 void PolicyLoaderWin::InitOnFile() { 465 void PolicyLoaderWin::InitOnFile() {
466 // Build the Chrome policy schema.
467 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue());
468 for (const PolicyDefinitionList::Entry* e = policy_list_->begin;
469 e != policy_list_->end; ++e) {
470 const std::string schema_type = GetSchemaTypeForValueType(e->value_type);
471 scoped_ptr<base::DictionaryValue> entry_schema(new base::DictionaryValue());
472 entry_schema->SetStringWithoutPathExpansion(json_schema_constants::kType,
473 schema_type);
474
475 if (e->value_type == base::Value::TYPE_LIST) {
476 scoped_ptr<base::DictionaryValue> items_schema(
477 new base::DictionaryValue());
478 items_schema->SetStringWithoutPathExpansion(
479 json_schema_constants::kType, json_schema_constants::kString);
480 entry_schema->SetWithoutPathExpansion(json_schema_constants::kItems,
481 items_schema.release());
482 }
483 properties->SetWithoutPathExpansion(e->name, entry_schema.release());
484 }
485 chrome_policy_schema_.SetStringWithoutPathExpansion(
486 json_schema_constants::kType, json_schema_constants::kObject);
487 chrome_policy_schema_.SetWithoutPathExpansion(
488 json_schema_constants::kProperties, properties.release());
Joao da Silva 2013/04/05 13:55:01 Using a DictionaryBuilder here may make this clean
Mattias Nissler (ping if slow) 2013/04/09 22:43:38 DictionaryBuilder is still in chrome/common/extens
489
413 is_initialized_ = true; 490 is_initialized_ = true;
414 SetupWatches(); 491 SetupWatches();
415 } 492 }
416 493
417 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { 494 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() {
418 scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
419 LoadChromePolicy(
420 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
421 Load3rdPartyPolicies(bundle.get());
422 return bundle.Pass();
423 }
424
425 void PolicyLoaderWin::LoadChromePolicy(PolicyMap* chrome_policies) {
426 // Reset the watches BEFORE reading the individual policies to avoid 495 // Reset the watches BEFORE reading the individual policies to avoid
427 // missing a change notification. 496 // missing a change notification.
428 if (is_initialized_) 497 if (is_initialized_)
429 SetupWatches(); 498 SetupWatches();
430 499
431 // |kKeyPaths| is in decreasing order of priority. 500 // Policy scope and corresponding hive.
432 static const struct { 501 static const struct {
433 const wchar_t* path; 502 PolicyScope scope;
434 PolicyLevel level; 503 HKEY hive;
435 } kKeyPaths[] = { 504 } kScopes[] = {
436 { kRegistryMandatorySubKey, POLICY_LEVEL_MANDATORY }, 505 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE },
437 { kRegistryRecommendedSubKey, POLICY_LEVEL_RECOMMENDED }, 506 { POLICY_SCOPE_USER, HKEY_CURRENT_USER },
438 }; 507 };
439 508
440 // Lookup at the mandatory path for both user and machine policies first, and 509 // Load policy data for the different scopes/levels and merge them.
441 // then at the recommended path. 510 scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
442 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { 511 PolicyMap* chrome_policy =
443 for (size_t h = 0; h < arraysize(kHives); ++h) { 512 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
444 // Iterate over keys and values at this hive and path. 513 for (size_t i = 0; i < arraysize(kScopes); ++i) {
445 HKEY hive = kHives[h].hive; 514 PolicyScope scope = kScopes[i].scope;
446 string16 path(kKeyPaths[k].path); 515 base::DictionaryValue gpo_dict;
447 RegKey key; 516 if (!ReadPolicyFromGPO(scope, &gpo_dict))
448 if (key.Open(hive, path.c_str(), KEY_READ) != ERROR_SUCCESS || 517 ReadRegistry(kScopes[i].hive, kRegistryChromePolicyKey, &gpo_dict);
449 !key.Valid()) { 518
519 // Remove special-cased entries from the GPO dictionary.
520 base::DictionaryValue* temp_dict = NULL;
521 scoped_ptr<base::DictionaryValue> recommended_dict(
522 RemoveDict(&gpo_dict, kKeyRecommended));
523 scoped_ptr<base::DictionaryValue> third_party_dict(
524 RemoveDict(&gpo_dict, kKeyThirdParty));
525
526 // Load Chrome policy.
527 LoadChromePolicy(&gpo_dict, POLICY_LEVEL_MANDATORY, scope, chrome_policy);
528 LoadChromePolicy(recommended_dict.get(), POLICY_LEVEL_RECOMMENDED, scope,
529 chrome_policy);
530
531 // Load 3rd-party policy.
532 if (third_party_dict)
533 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get());
534 }
535
536 return bundle.Pass();
537 }
538
539 void PolicyLoaderWin::LoadChromePolicy(const base::DictionaryValue* gpo_dict,
540 PolicyLevel level,
541 PolicyScope scope,
542 PolicyMap* chrome_policy_map) {
543 PolicyMap policy;
544 ParsePolicy(gpo_dict, level, scope, &chrome_policy_schema_, &policy);
545 chrome_policy_map->MergeFrom(policy);
546 }
547
548 void PolicyLoaderWin::Load3rdPartyPolicy(
549 const DictionaryValue* gpo_dict,
550 PolicyScope scope,
551 PolicyBundle* bundle) {
552 // Map of known 3rd party policy domain name to their enum values.
553 static const struct {
554 const char* name;
555 PolicyDomain domain;
556 } k3rdPartyDomains[] = {
557 { "extensions", POLICY_DOMAIN_EXTENSIONS },
558 };
559
560 // Policy level and corresponding path.
561 static const struct {
562 PolicyLevel level;
563 const char* path;
564 } kLevels[] = {
565 { POLICY_LEVEL_MANDATORY, kKeyMandatory },
566 { POLICY_LEVEL_RECOMMENDED, kKeyRecommended },
567 };
568
569 for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) {
570 const char* name = k3rdPartyDomains[i].name;
571 const PolicyDomain domain = k3rdPartyDomains[i].domain;
572 const base::DictionaryValue* domain_dict = NULL;
573 if (!gpo_dict->GetDictionaryWithoutPathExpansion(name, &domain_dict) ||
574 !domain_dict) {
575 continue;
576 }
577
578 for (base::DictionaryValue::Iterator component(*domain_dict);
579 component.HasNext(); component.Advance()) {
580 const base::DictionaryValue* component_dict = NULL;
581 if (!component.value().GetAsDictionary(&component_dict) ||
582 !component_dict) {
450 continue; 583 continue;
451 } 584 }
452 585
453 // Iterate over values for most policies. 586 // Load the schema.
454 for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { 587 scoped_ptr<base::Value> schema;
455 std::string name(UTF16ToUTF8(it.Name())); 588 const base::DictionaryValue* schema_dict = NULL;
456 // Skip if a higher-priority policy value was already inserted, or 589 std::string schema_json;
457 // if this is the default value (empty string). 590 if (component_dict->GetStringWithoutPathExpansion(kKeySchema,
458 if (chrome_policies->Get(name) || name.empty()) 591 &schema_json)) {
459 continue; 592 schema.reset(base::JSONReader::Read(schema_json));
460 // Get the expected policy type, if this is a known policy. 593 if (!schema || !schema->GetAsDictionary(&schema_dict)) {
461 base::Value::Type type = GetDefaultFor(it.Type()); 594 LOG(WARNING) << "Failed to parse 3rd-part policy schema for "
462 for (const PolicyDefinitionList::Entry* e = policy_list_->begin; 595 << domain << "/" << component.key();
463 e != policy_list_->end; ++e) {
464 if (name == e->name) {
465 type = e->value_type;
466 break;
467 }
468 } 596 }
469 base::Value* value = ReadPolicyValue(&key, it.Name(), it.Type(), type);
470 if (!value)
471 value = base::Value::CreateNullValue();
472 chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, value);
473 } 597 }
474 598
475 // Iterate over keys for policies of type string-list. 599 // Parse policy.
476 for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { 600 for (size_t j = 0; j < arraysize(kLevels); j++) {
477 std::string name(UTF16ToUTF8(it.Name())); 601 const base::DictionaryValue* policy_dict = NULL;
478 // Skip if a higher-priority policy value was already inserted, or 602 if (!component_dict->GetDictionaryWithoutPathExpansion(
479 // if this is the 3rd party policy subkey. 603 kLevels[j].path, &policy_dict) ||
480 const string16 kThirdParty16(kThirdParty); 604 !policy_dict) {
481 if (chrome_policies->Get(name) || it.Name() == kThirdParty16)
482 continue;
483 string16 list_path = path + kPathSep + it.Name();
484 RegKey key;
485 if (key.Open(hive, list_path.c_str(), KEY_READ) != ERROR_SUCCESS ||
486 !key.Valid()) {
487 continue; 605 continue;
488 } 606 }
489 base::ListValue* result = new base::ListValue(); 607
490 string16 value; 608 PolicyMap policy;
491 int index = 0; 609 ParsePolicy(policy_dict, kLevels[j].level, scope, schema_dict, &policy);
492 while (ReadRegistryString(&key, base::IntToString16(++index), &value)) 610 PolicyNamespace policy_namespace(domain, component.key());
493 result->Append(base::Value::CreateStringValue(value)); 611 bundle->Get(policy_namespace).MergeFrom(policy);
494 chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, result);
495 } 612 }
496 } 613 }
497 } 614 }
498 } 615 }
499
500 void PolicyLoaderWin::Load3rdPartyPolicies(PolicyBundle* bundle) {
501 // Each 3rd party namespace can have policies on both HKLM and HKCU. They
502 // should be merged, giving priority to HKLM for policies with the same name.
503
504 // Map of known domain name to their enum values.
505 static const struct {
506 const char* name;
507 PolicyDomain domain;
508 } kDomains[] = {
509 { "extensions", POLICY_DOMAIN_EXTENSIONS },
510 };
511
512 // Map of policy paths to their corresponding policy level, in decreasing
513 // order of priority.
514 static const struct {
515 const char* path;
516 PolicyLevel level;
517 } kKeyPaths[] = {
518 { "policy", POLICY_LEVEL_MANDATORY },
519 { "recommended", POLICY_LEVEL_RECOMMENDED },
520 };
521
522 // Path where policies for components are stored.
523 const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep +
524 kThirdParty + kPathSep;
525
526 for (size_t h = 0; h < arraysize(kHives); ++h) {
527 HKEY hkey = kHives[h].hive;
528
529 for (size_t d = 0; d < arraysize(kDomains); ++d) {
530 // Each subkey under this domain is a component of that domain.
531 // |domain_path| == SOFTWARE\Policies\Chromium\3rdparty\<domain>
532 string16 domain_path = kPathPrefix + ASCIIToUTF16(kDomains[d].name);
533
534 for (RegistryKeyIterator domain_iterator(hkey, domain_path.c_str());
535 domain_iterator.Valid(); ++domain_iterator) {
536 string16 component(domain_iterator.Name());
537 string16 component_path = domain_path + kPathSep + component;
538
539 // Load the schema for this component's policy, if present.
540 scoped_ptr<base::DictionaryValue> schema(
541 ReadRegistrySchema(hkey, component_path, kSchema));
542
543 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) {
544 string16 path =
545 component_path + kPathSep + ASCIIToUTF16(kKeyPaths[k].path);
546
547 scoped_ptr<base::DictionaryValue> dictionary(
548 ReadComponentDictionaryValue(hkey, path, schema.get()));
549 if (dictionary.get()) {
550 PolicyMap policies;
551 policies.LoadFrom(
552 dictionary.get(), kKeyPaths[k].level, kHives[h].scope);
553 // LoadFrom() overwrites any existing values. Use a temporary map
554 // and then use MergeFrom(), that only overwrites values with lower
555 // priority.
556 bundle->Get(PolicyNamespace(kDomains[d].domain,
557 UTF16ToUTF8(component)))
558 .MergeFrom(policies);
559 }
560 }
561 }
562 }
563 }
564 }
565 616
566 void PolicyLoaderWin::SetupWatches() { 617 void PolicyLoaderWin::SetupWatches() {
567 DCHECK(is_initialized_); 618 DCHECK(is_initialized_);
568 if (!user_policy_watcher_failed_ && 619 if (!user_policy_watcher_failed_ &&
569 !user_policy_watcher_.GetWatchedObject() && 620 !user_policy_watcher_.GetWatchedObject() &&
570 !user_policy_watcher_.StartWatching( 621 !user_policy_watcher_.StartWatching(
571 user_policy_changed_event_.handle(), this)) { 622 user_policy_changed_event_.handle(), this)) {
572 DLOG(WARNING) << "Failed to start watch for user policy change event"; 623 DLOG(WARNING) << "Failed to start watch for user policy change event";
573 user_policy_watcher_failed_ = true; 624 user_policy_watcher_failed_ = true;
574 } 625 }
575 if (!machine_policy_watcher_failed_ && 626 if (!machine_policy_watcher_failed_ &&
576 !machine_policy_watcher_.GetWatchedObject() && 627 !machine_policy_watcher_.GetWatchedObject() &&
577 !machine_policy_watcher_.StartWatching( 628 !machine_policy_watcher_.StartWatching(
578 machine_policy_changed_event_.handle(), this)) { 629 machine_policy_changed_event_.handle(), this)) {
579 DLOG(WARNING) << "Failed to start watch for machine policy change event"; 630 DLOG(WARNING) << "Failed to start watch for machine policy change event";
580 machine_policy_watcher_failed_ = true; 631 machine_policy_watcher_failed_ = true;
581 } 632 }
582 } 633 }
583 634
584 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { 635 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
585 DCHECK(object == user_policy_changed_event_.handle() || 636 DCHECK(object == user_policy_changed_event_.handle() ||
586 object == machine_policy_changed_event_.handle()) 637 object == machine_policy_changed_event_.handle())
587 << "unexpected object signaled policy reload, obj = " 638 << "unexpected object signaled policy reload, obj = "
588 << std::showbase << std::hex << object; 639 << std::showbase << std::hex << object;
589 Reload(false); 640 Reload(false);
590 } 641 }
591 642
592 } // namespace policy 643 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698