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

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: Rebase 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 #include <vector>
8 9
9 #include <string.h> 10 #include <rpc.h> // For struct GUID
11 #include <shlwapi.h> // For PathIsUNC()
12 #include <userenv.h> // For GPO functions
13 #include <windows.h>
10 14
11 #include <userenv.h> 15 // shlwapi.dll is required for PathIsUNC().
12 16 #pragma comment(lib, "shlwapi.lib")
13 // userenv.dll is required for RegisterGPNotification(). 17 // userenv.dll is required for various GPO functions.
14 #pragma comment(lib, "userenv.lib") 18 #pragma comment(lib, "userenv.lib")
15 19
16 #include "base/basictypes.h" 20 #include "base/basictypes.h"
21 #include "base/file_util.h"
22 #include "base/files/file_path.h"
17 #include "base/json/json_reader.h" 23 #include "base/json/json_reader.h"
24 #include "base/lazy_instance.h"
18 #include "base/logging.h" 25 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h" 26 #include "base/scoped_native_library.h"
27 #include "base/stl_util.h"
20 #include "base/string16.h" 28 #include "base/string16.h"
29 #include "base/string_util.h"
21 #include "base/strings/string_number_conversions.h" 30 #include "base/strings/string_number_conversions.h"
31 #include "base/sys_byteorder.h"
22 #include "base/utf_string_conversions.h" 32 #include "base/utf_string_conversions.h"
23 #include "base/values.h"
24 #include "base/win/registry.h" 33 #include "base/win/registry.h"
25 #include "chrome/browser/policy/policy_bundle.h" 34 #include "chrome/browser/policy/policy_bundle.h"
26 #include "chrome/browser/policy/policy_map.h" 35 #include "chrome/browser/policy/policy_map.h"
36 #include "chrome/browser/policy/preg_parser_win.h"
27 #include "chrome/common/json_schema/json_schema_constants.h" 37 #include "chrome/common/json_schema/json_schema_constants.h"
28 #include "policy/policy_constants.h" 38 #include "policy/policy_constants.h"
29 39
30 namespace schema = json_schema_constants; 40 namespace schema = json_schema_constants;
31 41
32 using base::win::RegKey; 42 using base::win::RegKey;
33 using base::win::RegistryKeyIterator; 43 using base::win::RegistryKeyIterator;
34 using base::win::RegistryValueIterator; 44 using base::win::RegistryValueIterator;
35 using namespace policy::registry_constants;
36 45
37 namespace policy { 46 namespace policy {
38 47
39 namespace registry_constants {
40 const wchar_t kPathSep[] = L"\\";
41 const wchar_t kThirdParty[] = L"3rdparty";
42 const wchar_t kMandatory[] = L"policy";
43 const wchar_t kRecommended[] = L"recommended";
44 const wchar_t kSchema[] = L"schema";
45 } // namespace registry_constants
46
47 namespace { 48 namespace {
48 49
49 // Map of registry hives to their corresponding policy scope, in decreasing 50 const char kKeyMandatory[] = "policy";
50 // order of priority. 51 const char kKeyRecommended[] = "recommended";
51 const struct { 52 const char kKeySchema[] = "schema";
52 HKEY hive; 53 const char kKeyThirdParty[] = "3rdparty";
53 PolicyScope scope; 54
54 } kHives[] = { 55 // The GUID of the registry settings group policy extension.
55 { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, 56 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID;
56 { HKEY_CURRENT_USER, POLICY_SCOPE_USER }, 57
58 // The PReg file name.
59 const base::FilePath::CharType kPRegFileName[] =
60 FILE_PATH_LITERAL("Registry.pol");
61
62 // A helper class encapsulating run-time-linked function calls to Wow64 APIs.
63 class Wow64Functions {
64 public:
65 Wow64Functions()
66 : kernel32_lib_(base::FilePath(L"kernel32")),
67 is_wow_64_process_(NULL),
68 wow_64_disable_wow_64_fs_redirection_(NULL),
69 wow_64_revert_wow_64_fs_redirection_(NULL) {
70 if (kernel32_lib_.is_valid()) {
71 is_wow_64_process_ = static_cast<IsWow64Process>(
72 kernel32_lib_.GetFunctionPointer("IsWow64Process"));
73 wow_64_disable_wow_64_fs_redirection_ =
74 static_cast<Wow64DisableWow64FSRedirection>(
75 kernel32_lib_.GetFunctionPointer(
76 "Wow64DisableWow64FsRedirection"));
77 wow_64_revert_wow_64_fs_redirection_ =
78 static_cast<Wow64RevertWow64FSRedirection>(
79 kernel32_lib_.GetFunctionPointer(
80 "Wow64RevertWow64FsRedirection"));
81 }
82 }
83
84 bool is_valid() {
85 return is_wow_64_process_ &&
86 wow_64_disable_wow_64_fs_redirection_ &&
87 wow_64_revert_wow_64_fs_redirection_;
88 }
89
90 bool IsWow64() {
91 BOOL result = 0;
92 if (!is_wow_64_process_(GetCurrentProcess(), &result))
93 PLOG(WARNING) << "IsWow64ProcFailed";
94 return !!result;
95 }
96
97 bool DisableFsRedirection(PVOID* previous_state) {
98 return !!wow_64_disable_wow_64_fs_redirection_(previous_state);
99 }
100
101 bool RevertFsRedirection(PVOID previous_state) {
102 return !!wow_64_revert_wow_64_fs_redirection_(previous_state);
103 }
104
105 private:
106 typedef BOOL (WINAPI* IsWow64Process)(HANDLE, PBOOL);
107 typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
108 typedef BOOL (WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
109
110 base::ScopedNativeLibrary kernel32_lib_;
111
112 IsWow64Process is_wow_64_process_;
113 Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection_;
114 Wow64RevertWow64FSRedirection wow_64_revert_wow_64_fs_redirection_;
115
116 DISALLOW_COPY_AND_ASSIGN(Wow64Functions);
57 }; 117 };
58 118
59 // Reads a REG_SZ string at |key| named |name| into |result|. Returns false if 119 // Global Wow64Function instance used by ScopedDisableWow64Redirection below.
60 // the string could not be read. 120 static base::LazyInstance<Wow64Functions> g_wow_64_functions =
61 bool ReadRegistryString(RegKey* key, 121 LAZY_INSTANCE_INITIALIZER;
62 const string16& name,
63 string16* result) {
64 DWORD value_size = 0;
65 DWORD key_type = 0;
66 scoped_array<uint8> buffer;
67 122
68 if (key->ReadValue(name.c_str(), 0, &value_size, &key_type) != ERROR_SUCCESS) 123 // Scoper that switches off Wow64 File System Redirection during its lifetime.
69 return false; 124 class ScopedDisableWow64Redirection {
70 if (key_type != REG_SZ) 125 public:
71 return false; 126 ScopedDisableWow64Redirection()
127 : active_(false),
128 previous_state_(NULL) {
129 Wow64Functions* wow64 = g_wow_64_functions.Pointer();
130 if (wow64->is_valid() && wow64->IsWow64()) {
131 if (wow64->DisableFsRedirection(&previous_state_))
132 active_ = true;
133 else
134 PLOG(WARNING) << "Wow64DisableWow64FSRedirection";
135 }
136 }
72 137
73 // According to the Microsoft documentation, the string 138 ~ScopedDisableWow64Redirection() {
74 // buffer may not be explicitly 0-terminated. Allocate a 139 if (active_)
75 // slightly larger buffer and pre-fill to zeros to guarantee 140 CHECK(g_wow_64_functions.Get().RevertFsRedirection(previous_state_));
76 // the 0-termination. 141 }
77 buffer.reset(new uint8[value_size + 2]); 142
78 memset(buffer.get(), 0, value_size + 2); 143 bool is_active() { return active_; }
79 key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL); 144
80 result->assign(reinterpret_cast<const wchar_t*>(buffer.get())); 145 private:
81 return true; 146 bool active_;
147 PVOID previous_state_;
148
149 DISALLOW_COPY_AND_ASSIGN(ScopedDisableWow64Redirection);
150 };
151
152 // AppliedGPOListProvider implementation that calls actual Windows APIs.
153 class WinGPOListProvider : public AppliedGPOListProvider {
154 public:
155 virtual ~WinGPOListProvider() {}
156
157 // AppliedGPOListProvider:
158 virtual DWORD GetAppliedGPOList(DWORD flags,
159 LPCTSTR machine_name,
160 PSID sid_user,
161 GUID* extension_guid,
162 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
163 return ::GetAppliedGPOList(flags, machine_name, sid_user, extension_guid,
164 gpo_list);
165 }
166
167 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
168 return ::FreeGPOList(gpo_list);
169 }
170 };
171
172 // The default windows GPO list provider used for PolicyLoaderWin.
173 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider =
174 LAZY_INSTANCE_INITIALIZER;
175
176 // Returns the entry with key |name| in |dictionary| (can be NULL), or NULL.
177 const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary,
178 const std::string& name) {
179 if (!dictionary)
180 return NULL;
181 const base::DictionaryValue* entry = NULL;
182 dictionary->GetDictionaryWithoutPathExpansion(name, &entry);
183 return entry;
82 } 184 }
83 185
84 // Reads a REG_DWORD integer at |key| named |name| into |result|. Returns false 186 // Tries to extract the dictionary at |key| in |dict| and returns it.
85 // if the value could no be read. 187 scoped_ptr<base::DictionaryValue> RemoveDict(base::DictionaryValue* dict,
86 bool ReadRegistryInteger(RegKey* key, 188 const std::string& key) {
87 const string16& name, 189 base::Value* entry = NULL;
88 uint32* result) { 190 base::DictionaryValue* result_dict = NULL;
89 DWORD dword; 191 if (dict && dict->RemoveWithoutPathExpansion(key, &entry) && entry) {
90 if (key->ReadValueDW(name.c_str(), &dword) != ERROR_SUCCESS) 192 if (!entry->GetAsDictionary(&result_dict))
91 return false; 193 delete entry;
92 *result = dword; 194 }
93 return true; 195
196 return make_scoped_ptr(result_dict);
197 }
198
199 std::string GetSchemaTypeForValueType(base::Value::Type value_type) {
200 switch (value_type) {
201 case base::Value::TYPE_DICTIONARY:
202 return json_schema_constants::kObject;
203 case base::Value::TYPE_INTEGER:
204 return json_schema_constants::kInteger;
205 case base::Value::TYPE_LIST:
206 return json_schema_constants::kArray;
207 case base::Value::TYPE_BOOLEAN:
208 return json_schema_constants::kBoolean;
209 case base::Value::TYPE_STRING:
210 return json_schema_constants::kString;
211 default:
212 break;
213 }
214
215 NOTREACHED() << "Unsupported policy value type " << value_type;
216 return json_schema_constants::kNull;
94 } 217 }
95 218
96 // Returns the Value type described in |schema|, or |default_type| if not found. 219 // Returns the Value type described in |schema|, or |default_type| if not found.
97 base::Value::Type GetType(const base::DictionaryValue* schema, 220 base::Value::Type GetValueTypeForSchema(const base::DictionaryValue* schema,
98 base::Value::Type default_type) { 221 base::Value::Type default_type) {
99 // JSON-schema types to base::Value::Type mapping. 222 // JSON-schema types to base::Value::Type mapping.
100 static const struct { 223 static const struct {
101 // JSON schema type. 224 // JSON schema type.
102 const char* schema_type; 225 const char* schema_type;
103 // Correspondent value type. 226 // Correspondent value type.
104 base::Value::Type value_type; 227 base::Value::Type value_type;
105 } kSchemaToValueTypeMap[] = { 228 } kSchemaToValueTypeMap[] = {
106 { schema::kArray, base::Value::TYPE_LIST }, 229 { schema::kArray, base::Value::TYPE_LIST },
107 { schema::kBoolean, base::Value::TYPE_BOOLEAN }, 230 { schema::kBoolean, base::Value::TYPE_BOOLEAN },
108 { schema::kInteger, base::Value::TYPE_INTEGER }, 231 { schema::kInteger, base::Value::TYPE_INTEGER },
109 { schema::kNull, base::Value::TYPE_NULL }, 232 { schema::kNull, base::Value::TYPE_NULL },
110 { schema::kNumber, base::Value::TYPE_DOUBLE }, 233 { schema::kNumber, base::Value::TYPE_DOUBLE },
111 { schema::kObject, base::Value::TYPE_DICTIONARY }, 234 { schema::kObject, base::Value::TYPE_DICTIONARY },
112 { schema::kString, base::Value::TYPE_STRING }, 235 { schema::kString, base::Value::TYPE_STRING },
113 }; 236 };
114 237
115 if (!schema) 238 if (!schema)
116 return default_type; 239 return default_type;
117 std::string type; 240 std::string type;
118 if (!schema->GetString(schema::kType, &type)) 241 if (!schema->GetStringWithoutPathExpansion(schema::kType, &type))
119 return default_type; 242 return default_type;
120 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { 243 for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) {
121 if (type == kSchemaToValueTypeMap[i].schema_type) 244 if (type == kSchemaToValueTypeMap[i].schema_type)
122 return kSchemaToValueTypeMap[i].value_type; 245 return kSchemaToValueTypeMap[i].value_type;
123 } 246 }
124 return default_type; 247 return default_type;
125 } 248 }
126 249
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. 250 // Returns the schema for property |name| given the |schema| of an object.
145 // Returns the "additionalProperties" schema if no specific schema for 251 // Returns the "additionalProperties" schema if no specific schema for
146 // |name| is present. Returns NULL if no schema is found. 252 // |name| is present. Returns NULL if no schema is found.
147 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, 253 const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema,
148 const std::string& name) { 254 const std::string& name) {
149 const base::DictionaryValue* properties = 255 const base::DictionaryValue* properties =
150 GetEntry(schema, schema::kProperties); 256 GetEntry(schema, schema::kProperties);
151 const base::DictionaryValue* sub_schema = GetEntry(properties, name); 257 const base::DictionaryValue* sub_schema = GetEntry(properties, name);
152 if (sub_schema) 258 if (sub_schema)
153 return sub_schema; 259 return sub_schema;
154 // "additionalProperties" can be a boolean, but that case is ignored. 260 // "additionalProperties" can be a boolean, but that case is ignored.
155 return GetEntry(schema, schema::kAdditionalProperties); 261 return GetEntry(schema, schema::kAdditionalProperties);
156 } 262 }
157 263
158 // Converts string |value| to another |type|, if possible. 264 // Reads the subtree of the Windows registry at |root| into the passed |dict|.
159 base::Value* ConvertStringValue(const string16& value, base::Value::Type type) { 265 void ReadRegistry(HKEY hive,
160 switch (type) { 266 const string16& root,
161 case base::Value::TYPE_NULL: 267 base::DictionaryValue* dict) {
162 return base::Value::CreateNullValue(); 268 // First, read all the values of the key.
163 269 for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) {
270 const std::string name = UTF16ToUTF8(it.Name());
271 switch (it.Type()) {
272 case REG_SZ:
273 case REG_EXPAND_SZ:
274 dict->SetStringWithoutPathExpansion(name, UTF16ToUTF8(it.Value()));
275 continue;
276 case REG_DWORD_LITTLE_ENDIAN:
277 case REG_DWORD_BIG_ENDIAN:
278 if (it.ValueSize() == sizeof(DWORD)) {
279 DWORD dword_value = *(reinterpret_cast<const DWORD*>(it.Value()));
280 if (it.Type() == REG_DWORD_BIG_ENDIAN)
281 dword_value = base::NetToHost32(dword_value);
282 else
283 dword_value = base::ByteSwapToLE32(dword_value);
284 dict->SetIntegerWithoutPathExpansion(name, dword_value);
285 continue;
286 }
287 case REG_NONE:
288 case REG_LINK:
289 case REG_MULTI_SZ:
290 case REG_RESOURCE_LIST:
291 case REG_FULL_RESOURCE_DESCRIPTOR:
292 case REG_RESOURCE_REQUIREMENTS_LIST:
293 case REG_QWORD_LITTLE_ENDIAN:
294 // Unsupported type, message gets logged below.
295 break;
296 }
297
298 LOG(WARNING) << "Failed to read hive " << hive << " at "
299 << root << "\\" << name
300 << " type " << it.Type();
301 }
302
303 // Recurse for all subkeys.
304 for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) {
305 std::string name(UTF16ToUTF8(it.Name()));
306 if (dict->HasKey(name)) {
307 DLOG(WARNING) << "Ignoring registry key because a value exists with the "
308 "same name: " << root << "\\" << name;
309 } else {
310 scoped_ptr<base::DictionaryValue> subdict(new base::DictionaryValue());
311 ReadRegistry(hive, root + L"\\" + it.Name(), subdict.get());
312 dict->SetWithoutPathExpansion(name, subdict.release());
313 }
314 }
315 }
316
317 // Converts |value| in raw GPO representation to the internal policy value, as
318 // described by |schema|. This maps the ambiguous GPO data types to the
319 // internal policy value representations.
320 scoped_ptr<base::Value> ConvertPolicyValue(
321 const base::Value& value,
322 const base::DictionaryValue* schema) {
323 // Figure out the type to convert to from the schema.
324 const base::Value::Type result_type(
325 GetValueTypeForSchema(schema, value.GetType()));
326
327 // If the type is good already, go with it.
328 if (value.IsType(result_type)) {
329 // Recurse for complex types if there is a schema.
330 if (schema) {
331 const base::DictionaryValue* dict = NULL;
332 const base::ListValue* list = NULL;
333 if (value.GetAsDictionary(&dict)) {
334 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
335 for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd();
336 entry.Advance()) {
337 scoped_ptr<base::Value> converted_value(
338 ConvertPolicyValue(entry.value(),
339 GetSchemaFor(schema, entry.key())));
340 result->SetWithoutPathExpansion(entry.key(),
341 converted_value.release());
342 }
343 return result.Pass();
344 } else if (value.GetAsList(&list)) {
345 scoped_ptr<base::ListValue> result(new base::ListValue());
346 const base::DictionaryValue* item_schema =
347 GetEntry(schema, schema::kItems);
348 for (base::ListValue::const_iterator entry(list->begin());
349 entry != list->end(); ++entry) {
350 result->Append(ConvertPolicyValue(**entry, item_schema).release());
351 }
352 return result.Pass();
353 }
354 }
355 return make_scoped_ptr(value.DeepCopy());
356 }
357
358 // Else, do some conversions to map windows registry data types to JSON types.
359 std::string string_value;
360 int int_value = 0;
361 switch (result_type) {
362 case base::Value::TYPE_NULL: {
363 return make_scoped_ptr(base::Value::CreateNullValue());
364 }
164 case base::Value::TYPE_BOOLEAN: { 365 case base::Value::TYPE_BOOLEAN: {
165 int int_value; 366 // Accept booleans encoded as either string or integer.
166 if (base::StringToInt(value, &int_value)) 367 if (value.GetAsInteger(&int_value) ||
167 return base::Value::CreateBooleanValue(int_value != 0); 368 (value.GetAsString(&string_value) &&
168 return NULL; 369 base::StringToInt(string_value, &int_value))) {
169 } 370 return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0));
170 371 }
372 break;
373 }
171 case base::Value::TYPE_INTEGER: { 374 case base::Value::TYPE_INTEGER: {
172 int int_value; 375 // Integers may be string-encoded.
173 if (base::StringToInt(value, &int_value)) 376 if (value.GetAsString(&string_value) &&
174 return base::Value::CreateIntegerValue(int_value); 377 base::StringToInt(string_value, &int_value)) {
175 return NULL; 378 return make_scoped_ptr(base::Value::CreateIntegerValue(int_value));
176 } 379 }
177 380 break;
381 }
178 case base::Value::TYPE_DOUBLE: { 382 case base::Value::TYPE_DOUBLE: {
179 double double_value; 383 // Doubles may be string-encoded or integer-encoded.
180 if (base::StringToDouble(UTF16ToUTF8(value), &double_value)) 384 double double_value = 0;
181 return base::Value::CreateDoubleValue(double_value); 385 if (value.GetAsInteger(&int_value)) {
182 DLOG(WARNING) << "Failed to read policy value as double: " << value; 386 return make_scoped_ptr(base::Value::CreateDoubleValue(int_value));
183 return NULL; 387 } else if (value.GetAsString(&string_value) &&
184 } 388 base::StringToDouble(string_value, &double_value)) {
185 389 return make_scoped_ptr(base::Value::CreateDoubleValue(double_value));
186 case base::Value::TYPE_STRING: 390 }
187 return base::Value::CreateStringValue(value); 391 break;
188 392 }
189 case base::Value::TYPE_DICTIONARY: 393 case base::Value::TYPE_LIST: {
190 case base::Value::TYPE_LIST: 394 // Lists are encoded as subkeys with numbered value in the registry.
191 return base::JSONReader::Read(UTF16ToUTF8(value)); 395 const base::DictionaryValue* dict = NULL;
192 396 if (value.GetAsDictionary(&dict)) {
193 case base::Value::TYPE_BINARY: 397 scoped_ptr<base::ListValue> result(new base::ListValue());
194 DLOG(WARNING) << "Cannot convert REG_SZ entry to type " << type; 398 const base::DictionaryValue* item_schema =
195 return NULL; 399 GetEntry(schema, schema::kItems);
196 } 400 for (int i = 1; ; ++i) {
197 NOTREACHED(); 401 const base::Value* entry = NULL;
198 return NULL; 402 if (!dict->Get(base::IntToString(i), &entry))
199 } 403 break;
200 404 result->Append(ConvertPolicyValue(*entry, item_schema).release());
201 // Converts an integer |value| to another |type|, if possible. 405 }
202 base::Value* ConvertIntegerValue(uint32 value, base::Value::Type type) { 406 return result.Pass();
203 switch (type) { 407 }
204 case base::Value::TYPE_BOOLEAN: 408 // Fall through in order to accept lists encoded as JSON strings.
205 return base::Value::CreateBooleanValue(value != 0); 409 }
206 410 case base::Value::TYPE_DICTIONARY: {
207 case base::Value::TYPE_INTEGER: 411 // Dictionaries may be encoded as JSON strings.
208 return base::Value::CreateIntegerValue(value); 412 if (value.GetAsString(&string_value)) {
209 413 scoped_ptr<base::Value> result(base::JSONReader::Read(string_value));
210 case base::Value::TYPE_DOUBLE: 414 if (result && result->IsType(result_type))
211 return base::Value::CreateDoubleValue(value); 415 return result.Pass();
212 416 }
213 case base::Value::TYPE_NULL: 417 break;
418 }
214 case base::Value::TYPE_STRING: 419 case base::Value::TYPE_STRING:
215 case base::Value::TYPE_BINARY: 420 case base::Value::TYPE_BINARY:
216 case base::Value::TYPE_DICTIONARY: 421 // No conversion possible.
217 case base::Value::TYPE_LIST: 422 break;
218 DLOG(WARNING) << "Cannot convert REG_DWORD entry to type " << type; 423 }
219 return NULL; 424
220 } 425 LOG(WARNING) << "Failed to convert " << value.GetType()
221 NOTREACHED(); 426 << " to " << result_type;
222 return NULL; 427 return make_scoped_ptr(base::Value::CreateNullValue());
223 } 428 }
224 429
225 // Reads a value from the registry |key| named |name| with registry type 430 // Parses |gpo_dict| according to |schema| and writes the resulting policy
226 // |registry_type| as a value of type |type|. 431 // settings to |policy| for the given |scope| and |level|.
227 // Returns NULL if the value could not be loaded or converted. 432 void ParsePolicy(const base::DictionaryValue* gpo_dict,
228 base::Value* ReadPolicyValue(RegKey* key, 433 PolicyLevel level,
229 const string16& name, 434 PolicyScope scope,
230 DWORD registry_type, 435 const base::DictionaryValue* schema,
231 base::Value::Type type) { 436 PolicyMap* policy) {
232 switch (registry_type) { 437 if (!gpo_dict)
233 case REG_SZ: { 438 return;
234 string16 value; 439
235 if (ReadRegistryString(key, name, &value)) 440 scoped_ptr<base::Value> policy_value(ConvertPolicyValue(*gpo_dict, schema));
236 return ConvertStringValue(value, type); 441 const base::DictionaryValue* policy_dict = NULL;
237 break; 442 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) {
238 } 443 LOG(WARNING) << "Root policy object is not a dictionary!";
239 444 return;
240 case REG_DWORD: { 445 }
241 uint32 value; 446
242 if (ReadRegistryInteger(key, name, &value)) 447 policy->LoadFrom(policy_dict, level, scope);
243 return ConvertIntegerValue(value, type);
244 break;
245 }
246
247 default:
248 DLOG(WARNING) << "Registry type not supported for key " << name;
249 break;
250 }
251 return NULL;
252 }
253
254 // Forward declaration for ReadComponentListValue().
255 base::DictionaryValue* ReadComponentDictionaryValue(
256 HKEY hive,
257 const string16& path,
258 const base::DictionaryValue* schema);
259
260 // Loads the list at |path| in the given |hive|. |schema| is a JSON schema
261 // (http://json-schema.org/) that describes the expected type of the list.
262 // Ownership of the result is transferred to the caller.
263 base::ListValue* ReadComponentListValue(HKEY hive,
264 const string16& path,
265 const base::DictionaryValue* schema) {
266 // The sub-elements are indexed from 1 to N. They can be represented as
267 // registry values or registry keys though; use |schema| first to try to
268 // determine the right type, and if that fails default to STRING.
269
270 RegKey key(hive, path.c_str(), KEY_READ);
271 if (!key.Valid())
272 return NULL;
273
274 // Get the schema for list items.
275 schema = GetEntry(schema, schema::kItems);
276 base::Value::Type type = GetType(schema, base::Value::TYPE_STRING);
277 base::ListValue* list = new base::ListValue();
278 for (int i = 1; ; ++i) {
279 string16 name = base::IntToString16(i);
280 base::Value* value = NULL;
281 if (type == base::Value::TYPE_DICTIONARY) {
282 value =
283 ReadComponentDictionaryValue(hive, path + kPathSep + name, schema);
284 } else if (type == base::Value::TYPE_LIST) {
285 value = ReadComponentListValue(hive, path + kPathSep + name, schema);
286 } else {
287 DWORD reg_type;
288 key.ReadValue(name.c_str(), NULL, NULL, &reg_type);
289 if (reg_type != REG_NONE)
290 value = ReadPolicyValue(&key, name, reg_type, type);
291 }
292 if (value)
293 list->Append(value);
294 else
295 break;
296 }
297 return list;
298 }
299
300 // Loads the dictionary at |path| in the given |hive|. |schema| is a JSON
301 // schema (http://json-schema.org/) that describes the expected types for the
302 // dictionary entries. When the type for a certain entry isn't described in the
303 // schema, a default conversion takes place. |schema| can be NULL.
304 // Ownership of the result is transferred to the caller.
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 } 448 }
387 449
388 } // namespace 450 } // namespace
389 451
390 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) 452 PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list,
453 const string16& chrome_policy_key,
454 AppliedGPOListProvider* gpo_provider)
391 : is_initialized_(false), 455 : is_initialized_(false),
392 policy_list_(policy_list), 456 policy_list_(policy_list),
457 chrome_policy_key_(chrome_policy_key),
458 gpo_provider_(gpo_provider),
393 user_policy_changed_event_(false, false), 459 user_policy_changed_event_(false, false),
394 machine_policy_changed_event_(false, false), 460 machine_policy_changed_event_(false, false),
395 user_policy_watcher_failed_(false), 461 user_policy_watcher_failed_(false),
396 machine_policy_watcher_failed_(false) { 462 machine_policy_watcher_failed_(false) {
397 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { 463 if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
398 DPLOG(WARNING) << "Failed to register user group policy notification"; 464 DPLOG(WARNING) << "Failed to register user group policy notification";
399 user_policy_watcher_failed_ = true; 465 user_policy_watcher_failed_ = true;
400 } 466 }
401 if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { 467 if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
402 DPLOG(WARNING) << "Failed to register machine group policy notification."; 468 DPLOG(WARNING) << "Failed to register machine group policy notification.";
403 machine_policy_watcher_failed_ = true; 469 machine_policy_watcher_failed_ = true;
404 } 470 }
405 } 471 }
406 472
407 PolicyLoaderWin::~PolicyLoaderWin() { 473 PolicyLoaderWin::~PolicyLoaderWin() {
408 user_policy_watcher_.StopWatching(); 474 user_policy_watcher_.StopWatching();
409 machine_policy_watcher_.StopWatching(); 475 machine_policy_watcher_.StopWatching();
410 } 476 }
411 477
478 // static
479 scoped_ptr<PolicyLoaderWin> PolicyLoaderWin::Create(
480 const PolicyDefinitionList* policy_list) {
481 return make_scoped_ptr(
482 new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey,
483 g_win_gpo_list_provider.Pointer()));
484 }
485
412 void PolicyLoaderWin::InitOnFile() { 486 void PolicyLoaderWin::InitOnFile() {
413 is_initialized_ = true; 487 is_initialized_ = true;
414 SetupWatches(); 488 SetupWatches();
415 } 489 }
416 490
417 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { 491 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 492 // Reset the watches BEFORE reading the individual policies to avoid
427 // missing a change notification. 493 // missing a change notification.
428 if (is_initialized_) 494 if (is_initialized_)
429 SetupWatches(); 495 SetupWatches();
430 496
431 // |kKeyPaths| is in decreasing order of priority. 497 if (chrome_policy_schema_.empty())
498 BuildChromePolicySchema();
499
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
448 if (key.Open(hive, path.c_str(), KEY_READ) != ERROR_SUCCESS || 517 HANDLE policy_lock =
449 !key.Valid()) { 518 EnterCriticalPolicySection(scope == POLICY_SCOPE_MACHINE);
450 continue; 519 if (policy_lock == NULL)
451 } 520 PLOG(ERROR) << "EnterCriticalPolicySection";
452 521
453 // Iterate over values for most policies. 522 if (!ReadPolicyFromGPO(scope, &gpo_dict)) {
454 for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { 523 VLOG(1) << "Failed to read GPO files for " << scope
455 std::string name(UTF16ToUTF8(it.Name())); 524 << " falling back to registry.";
456 // Skip if a higher-priority policy value was already inserted, or 525 ReadRegistry(kScopes[i].hive, chrome_policy_key_, &gpo_dict);
457 // if this is the default value (empty string). 526 }
458 if (chrome_policies->Get(name) || name.empty()) 527
459 continue; 528 if (!LeaveCriticalPolicySection(policy_lock))
460 // Get the expected policy type, if this is a known policy. 529 PLOG(ERROR) << "LeaveCriticalPolicySection";
461 base::Value::Type type = GetDefaultFor(it.Type()); 530
462 for (const PolicyDefinitionList::Entry* e = policy_list_->begin; 531 // Remove special-cased entries from the GPO dictionary.
463 e != policy_list_->end; ++e) { 532 base::DictionaryValue* temp_dict = NULL;
464 if (name == e->name) { 533 scoped_ptr<base::DictionaryValue> recommended_dict(
465 type = e->value_type; 534 RemoveDict(&gpo_dict, kKeyRecommended));
466 break; 535 scoped_ptr<base::DictionaryValue> third_party_dict(
467 } 536 RemoveDict(&gpo_dict, kKeyThirdParty));
468 } 537
469 base::Value* value = ReadPolicyValue(&key, it.Name(), it.Type(), type); 538 // Load Chrome policy.
470 if (!value) 539 LoadChromePolicy(&gpo_dict, POLICY_LEVEL_MANDATORY, scope, chrome_policy);
471 value = base::Value::CreateNullValue(); 540 LoadChromePolicy(recommended_dict.get(), POLICY_LEVEL_RECOMMENDED, scope,
472 chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, value); 541 chrome_policy);
473 } 542
474 543 // Load 3rd-party policy.
475 // Iterate over keys for policies of type string-list. 544 if (third_party_dict)
476 for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { 545 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get());
477 std::string name(UTF16ToUTF8(it.Name())); 546 }
478 // Skip if a higher-priority policy value was already inserted, or 547
479 // if this is the 3rd party policy subkey. 548 return bundle.Pass();
480 const string16 kThirdParty16(kThirdParty); 549 }
481 if (chrome_policies->Get(name) || it.Name() == kThirdParty16) 550
482 continue; 551 void PolicyLoaderWin::BuildChromePolicySchema() {
483 string16 list_path = path + kPathSep + it.Name(); 552 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue());
484 RegKey key; 553 for (const PolicyDefinitionList::Entry* e = policy_list_->begin;
485 if (key.Open(hive, list_path.c_str(), KEY_READ) != ERROR_SUCCESS || 554 e != policy_list_->end; ++e) {
486 !key.Valid()) { 555 const std::string schema_type = GetSchemaTypeForValueType(e->value_type);
487 continue; 556 scoped_ptr<base::DictionaryValue> entry_schema(new base::DictionaryValue());
488 } 557 entry_schema->SetStringWithoutPathExpansion(json_schema_constants::kType,
489 base::ListValue* result = new base::ListValue(); 558 schema_type);
490 string16 value; 559
491 int index = 0; 560 if (e->value_type == base::Value::TYPE_LIST) {
492 while (ReadRegistryString(&key, base::IntToString16(++index), &value)) 561 scoped_ptr<base::DictionaryValue> items_schema(
493 result->Append(base::Value::CreateStringValue(value)); 562 new base::DictionaryValue());
494 chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, result); 563 items_schema->SetStringWithoutPathExpansion(
495 } 564 json_schema_constants::kType, json_schema_constants::kString);
496 } 565 entry_schema->SetWithoutPathExpansion(json_schema_constants::kItems,
497 } 566 items_schema.release());
498 } 567 }
499 568 properties->SetWithoutPathExpansion(e->name, entry_schema.release());
500 void PolicyLoaderWin::Load3rdPartyPolicies(PolicyBundle* bundle) { 569 }
501 // Each 3rd party namespace can have policies on both HKLM and HKCU. They 570 chrome_policy_schema_.SetStringWithoutPathExpansion(
502 // should be merged, giving priority to HKLM for policies with the same name. 571 json_schema_constants::kType, json_schema_constants::kObject);
503 572 chrome_policy_schema_.SetWithoutPathExpansion(
504 // Map of known domain name to their enum values. 573 json_schema_constants::kProperties, properties.release());
574 }
575
576 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file,
577 base::DictionaryValue* policy) {
578 // The following deals with the minor annoyance that Wow64 FS redirection
579 // might need to be turned off: This is the case if running as a 32-bit
580 // process on a 64-bit system, in which case Wow64 FS redirection redirects
581 // access to the %WINDIR%/System32/GroupPolicy directory to
582 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the
583 // system-native directory.
584 if (file_util::PathExists(preg_file)) {
585 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy);
586 } else {
587 // Try with redirection switched off.
588 ScopedDisableWow64Redirection redirection_disable;
589 if (redirection_disable.is_active() && file_util::PathExists(preg_file))
590 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy);
591 }
592
593 // Report the error.
594 LOG(ERROR) << "PReg file doesn't exist: " << preg_file.value();
595 return false;
596 }
597
598 bool PolicyLoaderWin::LoadGPOPolicy(PolicyScope scope,
599 PGROUP_POLICY_OBJECT policy_object_list,
600 base::DictionaryValue* policy) {
601 base::DictionaryValue parsed_policy;
602 base::DictionaryValue forced_policy;
603 for (GROUP_POLICY_OBJECT* policy_object = policy_object_list;
604 policy_object; policy_object = policy_object->pNext) {
605 if (policy_object->dwOptions & GPO_FLAG_DISABLE)
606 continue;
607
608 if (PathIsUNC(policy_object->lpFileSysPath)) {
609 // UNC path: Assume this is an AD-managed machine, which updates the
610 // registry via GPO's standard registry CSE periodically. Fall back to
611 // reading from the registry in this case.
612 return false;
613 }
614
615 base::FilePath preg_file_path(
616 base::FilePath(policy_object->lpFileSysPath).Append(kPRegFileName));
617 if (policy_object->dwOptions & GPO_FLAG_FORCE) {
618 base::DictionaryValue new_forced_policy;
619 if (!ReadPRegFile(preg_file_path, &new_forced_policy))
620 return false;
621
622 // Merge with existing forced policy, giving precedence to the existing
623 // forced policy.
624 new_forced_policy.MergeDictionary(&forced_policy);
625 forced_policy.Swap(&new_forced_policy);
626 } else {
627 if (!ReadPRegFile(preg_file_path, &parsed_policy))
628 return false;
629 }
630 }
631
632 // Merge, give precedence to forced policy.
633 parsed_policy.MergeDictionary(&forced_policy);
634 policy->Swap(&parsed_policy);
635
636 return true;
637 }
638
639
640 bool PolicyLoaderWin::ReadPolicyFromGPO(PolicyScope scope,
641 base::DictionaryValue* policy) {
642 PGROUP_POLICY_OBJECT policy_object_list = NULL;
643 DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0;
644 if (gpo_provider_->GetAppliedGPOList(
645 flags, NULL, NULL, &kRegistrySettingsCSEGUID,
646 &policy_object_list) != ERROR_SUCCESS) {
647 PLOG(ERROR) << "GetAppliedGPOList scope " << scope;
648 return false;
649 }
650
651 bool result = LoadGPOPolicy(scope, policy_object_list, policy);
652 if (!gpo_provider_->FreeGPOList(policy_object_list))
653 LOG(WARNING) << "FreeGPOList";
654
655 return result;
656 }
657
658 void PolicyLoaderWin::LoadChromePolicy(const base::DictionaryValue* gpo_dict,
659 PolicyLevel level,
660 PolicyScope scope,
661 PolicyMap* chrome_policy_map) {
662 PolicyMap policy;
663 ParsePolicy(gpo_dict, level, scope, &chrome_policy_schema_, &policy);
664 chrome_policy_map->MergeFrom(policy);
665 }
666
667 void PolicyLoaderWin::Load3rdPartyPolicy(
668 const DictionaryValue* gpo_dict,
669 PolicyScope scope,
670 PolicyBundle* bundle) {
671 // Map of known 3rd party policy domain name to their enum values.
505 static const struct { 672 static const struct {
506 const char* name; 673 const char* name;
507 PolicyDomain domain; 674 PolicyDomain domain;
508 } kDomains[] = { 675 } k3rdPartyDomains[] = {
509 { "extensions", POLICY_DOMAIN_EXTENSIONS }, 676 { "extensions", POLICY_DOMAIN_EXTENSIONS },
510 }; 677 };
511 678
512 // Map of policy paths to their corresponding policy level, in decreasing 679 // Policy level and corresponding path.
513 // order of priority.
514 static const struct { 680 static const struct {
681 PolicyLevel level;
515 const char* path; 682 const char* path;
516 PolicyLevel level; 683 } kLevels[] = {
517 } kKeyPaths[] = { 684 { POLICY_LEVEL_MANDATORY, kKeyMandatory },
518 { "policy", POLICY_LEVEL_MANDATORY }, 685 { POLICY_LEVEL_RECOMMENDED, kKeyRecommended },
519 { "recommended", POLICY_LEVEL_RECOMMENDED },
520 }; 686 };
521 687
522 // Path where policies for components are stored. 688 for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) {
523 const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep + 689 const char* name = k3rdPartyDomains[i].name;
524 kThirdParty + kPathSep; 690 const PolicyDomain domain = k3rdPartyDomains[i].domain;
525 691 const base::DictionaryValue* domain_dict = NULL;
526 for (size_t h = 0; h < arraysize(kHives); ++h) { 692 if (!gpo_dict->GetDictionaryWithoutPathExpansion(name, &domain_dict) ||
527 HKEY hkey = kHives[h].hive; 693 !domain_dict) {
528 694 continue;
529 for (size_t d = 0; d < arraysize(kDomains); ++d) { 695 }
530 // Each subkey under this domain is a component of that domain. 696
531 // |domain_path| == SOFTWARE\Policies\Chromium\3rdparty\<domain> 697 for (base::DictionaryValue::Iterator component(*domain_dict);
532 string16 domain_path = kPathPrefix + ASCIIToUTF16(kDomains[d].name); 698 !component.IsAtEnd(); component.Advance()) {
533 699 const base::DictionaryValue* component_dict = NULL;
534 for (RegistryKeyIterator domain_iterator(hkey, domain_path.c_str()); 700 if (!component.value().GetAsDictionary(&component_dict) ||
535 domain_iterator.Valid(); ++domain_iterator) { 701 !component_dict) {
536 string16 component(domain_iterator.Name()); 702 continue;
537 string16 component_path = domain_path + kPathSep + component; 703 }
538 704
539 // Load the schema for this component's policy, if present. 705 // Load the schema.
540 scoped_ptr<base::DictionaryValue> schema( 706 scoped_ptr<base::Value> schema;
541 ReadRegistrySchema(hkey, component_path, kSchema)); 707 const base::DictionaryValue* schema_dict = NULL;
542 708 std::string schema_json;
543 for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { 709 if (component_dict->GetStringWithoutPathExpansion(kKeySchema,
544 string16 path = 710 &schema_json)) {
545 component_path + kPathSep + ASCIIToUTF16(kKeyPaths[k].path); 711 schema.reset(base::JSONReader::Read(schema_json));
546 712 if (!schema || !schema->GetAsDictionary(&schema_dict)) {
547 scoped_ptr<base::DictionaryValue> dictionary( 713 LOG(WARNING) << "Failed to parse 3rd-part policy schema for "
548 ReadComponentDictionaryValue(hkey, path, schema.get())); 714 << domain << "/" << component.key();
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 } 715 }
561 } 716 }
562 } 717
563 } 718 // Parse policy.
719 for (size_t j = 0; j < arraysize(kLevels); j++) {
720 const base::DictionaryValue* policy_dict = NULL;
721 if (!component_dict->GetDictionaryWithoutPathExpansion(
722 kLevels[j].path, &policy_dict) ||
723 !policy_dict) {
724 continue;
725 }
726
727 PolicyMap policy;
728 ParsePolicy(policy_dict, kLevels[j].level, scope, schema_dict, &policy);
729 PolicyNamespace policy_namespace(domain, component.key());
730 bundle->Get(policy_namespace).MergeFrom(policy);
731 }
732 }
733 }
564 } 734 }
565 735
566 void PolicyLoaderWin::SetupWatches() { 736 void PolicyLoaderWin::SetupWatches() {
567 DCHECK(is_initialized_); 737 DCHECK(is_initialized_);
568 if (!user_policy_watcher_failed_ && 738 if (!user_policy_watcher_failed_ &&
569 !user_policy_watcher_.GetWatchedObject() && 739 !user_policy_watcher_.GetWatchedObject() &&
570 !user_policy_watcher_.StartWatching( 740 !user_policy_watcher_.StartWatching(
571 user_policy_changed_event_.handle(), this)) { 741 user_policy_changed_event_.handle(), this)) {
572 DLOG(WARNING) << "Failed to start watch for user policy change event"; 742 DLOG(WARNING) << "Failed to start watch for user policy change event";
573 user_policy_watcher_failed_ = true; 743 user_policy_watcher_failed_ = true;
574 } 744 }
575 if (!machine_policy_watcher_failed_ && 745 if (!machine_policy_watcher_failed_ &&
576 !machine_policy_watcher_.GetWatchedObject() && 746 !machine_policy_watcher_.GetWatchedObject() &&
577 !machine_policy_watcher_.StartWatching( 747 !machine_policy_watcher_.StartWatching(
578 machine_policy_changed_event_.handle(), this)) { 748 machine_policy_changed_event_.handle(), this)) {
579 DLOG(WARNING) << "Failed to start watch for machine policy change event"; 749 DLOG(WARNING) << "Failed to start watch for machine policy change event";
580 machine_policy_watcher_failed_ = true; 750 machine_policy_watcher_failed_ = true;
581 } 751 }
582 } 752 }
583 753
584 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { 754 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
585 DCHECK(object == user_policy_changed_event_.handle() || 755 DCHECK(object == user_policy_changed_event_.handle() ||
586 object == machine_policy_changed_event_.handle()) 756 object == machine_policy_changed_event_.handle())
587 << "unexpected object signaled policy reload, obj = " 757 << "unexpected object signaled policy reload, obj = "
588 << std::showbase << std::hex << object; 758 << std::showbase << std::hex << object;
589 Reload(false); 759 Reload(false);
590 } 760 }
591 761
592 } // namespace policy 762 } // 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