OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "components/policy/core/common/preg_parser_win.h" | 5 #include "components/policy/core/common/preg_parser_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <stddef.h> |
| 9 #include <stdint.h> |
8 | 10 |
9 #include <algorithm> | 11 #include <algorithm> |
10 #include <functional> | 12 #include <functional> |
11 #include <iterator> | 13 #include <iterator> |
12 #include <vector> | 14 #include <vector> |
13 | 15 |
14 #include "base/basictypes.h" | |
15 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
16 #include "base/files/memory_mapped_file.h" | 17 #include "base/files/memory_mapped_file.h" |
17 #include "base/i18n/case_conversion.h" | 18 #include "base/i18n/case_conversion.h" |
18 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/macros.h" |
19 #include "base/strings/string16.h" | 21 #include "base/strings/string16.h" |
20 #include "base/strings/string_split.h" | 22 #include "base/strings/string_split.h" |
21 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
22 #include "base/strings/utf_string_conversions.h" | 24 #include "base/strings/utf_string_conversions.h" |
23 #include "base/sys_byteorder.h" | 25 #include "base/sys_byteorder.h" |
24 #include "base/values.h" | 26 #include "base/values.h" |
25 #include "components/policy/core/common/policy_load_status.h" | 27 #include "components/policy/core/common/policy_load_status.h" |
26 #include "components/policy/core/common/registry_dict_win.h" | 28 #include "components/policy/core/common/registry_dict_win.h" |
27 | 29 |
28 namespace policy { | 30 namespace policy { |
29 namespace preg_parser { | 31 namespace preg_parser { |
30 | 32 |
31 const char kPRegFileHeader[8] = | 33 const char kPRegFileHeader[8] = |
32 { 'P', 'R', 'e', 'g', '\x01', '\x00', '\x00', '\x00' }; | 34 { 'P', 'R', 'e', 'g', '\x01', '\x00', '\x00', '\x00' }; |
33 | 35 |
34 // Maximum PReg file size we're willing to accept. | 36 // Maximum PReg file size we're willing to accept. |
35 const int64 kMaxPRegFileSize = 1024 * 1024 * 16; | 37 const int64_t kMaxPRegFileSize = 1024 * 1024 * 16; |
36 | 38 |
37 // Constants for PReg file delimiters. | 39 // Constants for PReg file delimiters. |
38 const base::char16 kDelimBracketOpen = L'['; | 40 const base::char16 kDelimBracketOpen = L'['; |
39 const base::char16 kDelimBracketClose = L']'; | 41 const base::char16 kDelimBracketClose = L']'; |
40 const base::char16 kDelimSemicolon = L';'; | 42 const base::char16 kDelimSemicolon = L';'; |
41 | 43 |
42 // Registry path separator. | 44 // Registry path separator. |
43 const base::char16 kRegistryPathSeparator[] = L"\\"; | 45 const base::char16 kRegistryPathSeparator[] = L"\\"; |
44 | 46 |
45 // Magic strings for the PReg value field to trigger special actions. | 47 // Magic strings for the PReg value field to trigger special actions. |
46 const char kActionTriggerPrefix[] = "**"; | 48 const char kActionTriggerPrefix[] = "**"; |
47 const char kActionTriggerDeleteValues[] = "deletevalues"; | 49 const char kActionTriggerDeleteValues[] = "deletevalues"; |
48 const char kActionTriggerDel[] = "del."; | 50 const char kActionTriggerDel[] = "del."; |
49 const char kActionTriggerDelVals[] = "delvals"; | 51 const char kActionTriggerDelVals[] = "delvals"; |
50 const char kActionTriggerDeleteKeys[] = "deletekeys"; | 52 const char kActionTriggerDeleteKeys[] = "deletekeys"; |
51 const char kActionTriggerSecureKey[] = "securekey"; | 53 const char kActionTriggerSecureKey[] = "securekey"; |
52 const char kActionTriggerSoft[] = "soft"; | 54 const char kActionTriggerSoft[] = "soft"; |
53 | 55 |
54 // Returns the character at |cursor| and increments it, unless the end is here | 56 // Returns the character at |cursor| and increments it, unless the end is here |
55 // in which case -1 is returned. | 57 // in which case -1 is returned. |
56 int NextChar(const uint8** cursor, const uint8* end) { | 58 int NextChar(const uint8_t** cursor, const uint8_t* end) { |
57 // Only read the character if a full base::char16 is available. | 59 // Only read the character if a full base::char16 is available. |
58 if (*cursor + sizeof(base::char16) > end) | 60 if (*cursor + sizeof(base::char16) > end) |
59 return -1; | 61 return -1; |
60 | 62 |
61 int result = **cursor | (*(*cursor + 1) << 8); | 63 int result = **cursor | (*(*cursor + 1) << 8); |
62 *cursor += sizeof(base::char16); | 64 *cursor += sizeof(base::char16); |
63 return result; | 65 return result; |
64 } | 66 } |
65 | 67 |
66 // Reads a fixed-size field from a PReg file. | 68 // Reads a fixed-size field from a PReg file. |
67 bool ReadFieldBinary(const uint8** cursor, | 69 bool ReadFieldBinary(const uint8_t** cursor, |
68 const uint8* end, | 70 const uint8_t* end, |
69 uint32 size, | 71 uint32_t size, |
70 uint8* data) { | 72 uint8_t* data) { |
71 if (size == 0) | 73 if (size == 0) |
72 return true; | 74 return true; |
73 | 75 |
74 const uint8* field_end = *cursor + size; | 76 const uint8_t* field_end = *cursor + size; |
75 if (field_end <= *cursor || field_end > end) | 77 if (field_end <= *cursor || field_end > end) |
76 return false; | 78 return false; |
77 std::copy(*cursor, field_end, data); | 79 std::copy(*cursor, field_end, data); |
78 *cursor = field_end; | 80 *cursor = field_end; |
79 return true; | 81 return true; |
80 } | 82 } |
81 | 83 |
82 bool ReadField32(const uint8** cursor, const uint8* end, uint32* data) { | 84 bool ReadField32(const uint8_t** cursor, const uint8_t* end, uint32_t* data) { |
83 uint32 value = 0; | 85 uint32_t value = 0; |
84 if (!ReadFieldBinary(cursor, end, sizeof(uint32), | 86 if (!ReadFieldBinary(cursor, end, sizeof(uint32_t), |
85 reinterpret_cast<uint8*>(&value))) { | 87 reinterpret_cast<uint8_t*>(&value))) { |
86 return false; | 88 return false; |
87 } | 89 } |
88 *data = base::ByteSwapToLE32(value); | 90 *data = base::ByteSwapToLE32(value); |
89 return true; | 91 return true; |
90 } | 92 } |
91 | 93 |
92 // Reads a string field from a file. | 94 // Reads a string field from a file. |
93 bool ReadFieldString(const uint8** cursor, | 95 bool ReadFieldString(const uint8_t** cursor, |
94 const uint8* end, | 96 const uint8_t* end, |
95 base::string16* str) { | 97 base::string16* str) { |
96 int current = -1; | 98 int current = -1; |
97 while ((current = NextChar(cursor, end)) > 0x0000) | 99 while ((current = NextChar(cursor, end)) > 0x0000) |
98 *str += current; | 100 *str += current; |
99 | 101 |
100 return current == L'\0'; | 102 return current == L'\0'; |
101 } | 103 } |
102 | 104 |
103 std::string DecodePRegStringValue(const std::vector<uint8>& data) { | 105 std::string DecodePRegStringValue(const std::vector<uint8_t>& data) { |
104 size_t len = data.size() / sizeof(base::char16); | 106 size_t len = data.size() / sizeof(base::char16); |
105 if (len <= 0) | 107 if (len <= 0) |
106 return std::string(); | 108 return std::string(); |
107 | 109 |
108 const base::char16* chars = | 110 const base::char16* chars = |
109 reinterpret_cast<const base::char16*>(data.data()); | 111 reinterpret_cast<const base::char16*>(data.data()); |
110 base::string16 result; | 112 base::string16 result; |
111 std::transform(chars, chars + len - 1, std::back_inserter(result), | 113 std::transform(chars, chars + len - 1, std::back_inserter(result), |
112 std::ptr_fun(base::ByteSwapToLE16)); | 114 std::ptr_fun(base::ByteSwapToLE16)); |
113 return base::UTF16ToUTF8(result); | 115 return base::UTF16ToUTF8(result); |
114 } | 116 } |
115 | 117 |
116 // Decodes a value from a PReg file given as a uint8 vector. | 118 // Decodes a value from a PReg file given as a uint8_t vector. |
117 bool DecodePRegValue(uint32 type, | 119 bool DecodePRegValue(uint32_t type, |
118 const std::vector<uint8>& data, | 120 const std::vector<uint8_t>& data, |
119 scoped_ptr<base::Value>* value) { | 121 scoped_ptr<base::Value>* value) { |
120 switch (type) { | 122 switch (type) { |
121 case REG_SZ: | 123 case REG_SZ: |
122 case REG_EXPAND_SZ: | 124 case REG_EXPAND_SZ: |
123 value->reset(new base::StringValue(DecodePRegStringValue(data))); | 125 value->reset(new base::StringValue(DecodePRegStringValue(data))); |
124 return true; | 126 return true; |
125 case REG_DWORD_LITTLE_ENDIAN: | 127 case REG_DWORD_LITTLE_ENDIAN: |
126 case REG_DWORD_BIG_ENDIAN: | 128 case REG_DWORD_BIG_ENDIAN: |
127 if (data.size() == sizeof(uint32)) { | 129 if (data.size() == sizeof(uint32_t)) { |
128 uint32 val = *reinterpret_cast<const uint32*>(data.data()); | 130 uint32_t val = *reinterpret_cast<const uint32_t*>(data.data()); |
129 if (type == REG_DWORD_BIG_ENDIAN) | 131 if (type == REG_DWORD_BIG_ENDIAN) |
130 val = base::NetToHost32(val); | 132 val = base::NetToHost32(val); |
131 else | 133 else |
132 val = base::ByteSwapToLE32(val); | 134 val = base::ByteSwapToLE32(val); |
133 value->reset(new base::FundamentalValue(static_cast<int>(val))); | 135 value->reset(new base::FundamentalValue(static_cast<int>(val))); |
134 return true; | 136 return true; |
135 } else { | 137 } else { |
136 LOG(ERROR) << "Bad data size " << data.size(); | 138 LOG(ERROR) << "Bad data size " << data.size(); |
137 } | 139 } |
138 break; | 140 break; |
139 case REG_NONE: | 141 case REG_NONE: |
140 case REG_LINK: | 142 case REG_LINK: |
141 case REG_MULTI_SZ: | 143 case REG_MULTI_SZ: |
142 case REG_RESOURCE_LIST: | 144 case REG_RESOURCE_LIST: |
143 case REG_FULL_RESOURCE_DESCRIPTOR: | 145 case REG_FULL_RESOURCE_DESCRIPTOR: |
144 case REG_RESOURCE_REQUIREMENTS_LIST: | 146 case REG_RESOURCE_REQUIREMENTS_LIST: |
145 case REG_QWORD_LITTLE_ENDIAN: | 147 case REG_QWORD_LITTLE_ENDIAN: |
146 default: | 148 default: |
147 LOG(ERROR) << "Unsupported registry data type " << type; | 149 LOG(ERROR) << "Unsupported registry data type " << type; |
148 } | 150 } |
149 | 151 |
150 return false; | 152 return false; |
151 } | 153 } |
152 | 154 |
153 // Adds the record data passed via parameters to |dict| in case the data is | 155 // Adds the record data passed via parameters to |dict| in case the data is |
154 // relevant policy for Chromium. | 156 // relevant policy for Chromium. |
155 void HandleRecord(const base::string16& key_name, | 157 void HandleRecord(const base::string16& key_name, |
156 const base::string16& value, | 158 const base::string16& value, |
157 uint32 type, | 159 uint32_t type, |
158 const std::vector<uint8>& data, | 160 const std::vector<uint8_t>& data, |
159 RegistryDict* dict) { | 161 RegistryDict* dict) { |
160 // Locate/create the dictionary to place the value in. | 162 // Locate/create the dictionary to place the value in. |
161 std::vector<base::string16> path; | 163 std::vector<base::string16> path; |
162 | 164 |
163 for (const base::string16& entry : | 165 for (const base::string16& entry : |
164 base::SplitString(key_name, kRegistryPathSeparator, | 166 base::SplitString(key_name, kRegistryPathSeparator, |
165 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { | 167 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { |
166 if (entry.empty()) | 168 if (entry.empty()) |
167 continue; | 169 continue; |
168 const std::string name = base::UTF16ToUTF8(entry); | 170 const std::string name = base::UTF16ToUTF8(entry); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 if (mapped_file.length() < kHeaderSize || | 243 if (mapped_file.length() < kHeaderSize || |
242 memcmp(kPRegFileHeader, mapped_file.data(), kHeaderSize) != 0) { | 244 memcmp(kPRegFileHeader, mapped_file.data(), kHeaderSize) != 0) { |
243 LOG(ERROR) << "Bad policy file " << file_path.value(); | 245 LOG(ERROR) << "Bad policy file " << file_path.value(); |
244 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR); | 246 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR); |
245 return false; | 247 return false; |
246 } | 248 } |
247 | 249 |
248 // Parse file contents, which is UCS-2 and little-endian. The latter I | 250 // Parse file contents, which is UCS-2 and little-endian. The latter I |
249 // couldn't find documentation on, but the example I saw were all | 251 // couldn't find documentation on, but the example I saw were all |
250 // little-endian. It'd be interesting to check on big-endian hardware. | 252 // little-endian. It'd be interesting to check on big-endian hardware. |
251 const uint8* cursor = mapped_file.data() + kHeaderSize; | 253 const uint8_t* cursor = mapped_file.data() + kHeaderSize; |
252 const uint8* end = mapped_file.data() + mapped_file.length(); | 254 const uint8_t* end = mapped_file.data() + mapped_file.length(); |
253 while (true) { | 255 while (true) { |
254 if (cursor == end) | 256 if (cursor == end) |
255 return true; | 257 return true; |
256 | 258 |
257 if (NextChar(&cursor, end) != kDelimBracketOpen) | 259 if (NextChar(&cursor, end) != kDelimBracketOpen) |
258 break; | 260 break; |
259 | 261 |
260 // Read the record fields. | 262 // Read the record fields. |
261 base::string16 key_name; | 263 base::string16 key_name; |
262 base::string16 value; | 264 base::string16 value; |
263 uint32 type = 0; | 265 uint32_t type = 0; |
264 uint32 size = 0; | 266 uint32_t size = 0; |
265 std::vector<uint8> data; | 267 std::vector<uint8_t> data; |
266 | 268 |
267 if (!ReadFieldString(&cursor, end, &key_name)) | 269 if (!ReadFieldString(&cursor, end, &key_name)) |
268 break; | 270 break; |
269 | 271 |
270 int current = NextChar(&cursor, end); | 272 int current = NextChar(&cursor, end); |
271 if (current == kDelimSemicolon) { | 273 if (current == kDelimSemicolon) { |
272 if (!ReadFieldString(&cursor, end, &value)) | 274 if (!ReadFieldString(&cursor, end, &value)) |
273 break; | 275 break; |
274 current = NextChar(&cursor, end); | 276 current = NextChar(&cursor, end); |
275 } | 277 } |
(...skipping 23 matching lines...) Expand all Loading... |
299 break; | 301 break; |
300 | 302 |
301 // Process the record if it is within the |root| subtree. | 303 // Process the record if it is within the |root| subtree. |
302 if (base::StartsWith(base::i18n::ToLower(key_name), | 304 if (base::StartsWith(base::i18n::ToLower(key_name), |
303 base::i18n::ToLower(root), | 305 base::i18n::ToLower(root), |
304 base::CompareCase::SENSITIVE)) | 306 base::CompareCase::SENSITIVE)) |
305 HandleRecord(key_name.substr(root.size()), value, type, data, dict); | 307 HandleRecord(key_name.substr(root.size()), value, type, data, dict); |
306 } | 308 } |
307 | 309 |
308 LOG(ERROR) << "Error parsing " << file_path.value() << " at offset " | 310 LOG(ERROR) << "Error parsing " << file_path.value() << " at offset " |
309 << reinterpret_cast<const uint8*>(cursor - 1) - mapped_file.data(); | 311 << reinterpret_cast<const uint8_t*>(cursor - 1) - |
| 312 mapped_file.data(); |
310 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR); | 313 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR); |
311 return false; | 314 return false; |
312 } | 315 } |
313 | 316 |
314 } // namespace preg_parser | 317 } // namespace preg_parser |
315 } // namespace policy | 318 } // namespace policy |
OLD | NEW |