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

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

Issue 109743002: Move policy code into components/policy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: moar fixes Created 7 years 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/policy/preg_parser_win.h"
6
7 #include <windows.h>
8
9 #include <algorithm>
10 #include <iterator>
11 #include <vector>
12
13 #include "base/basictypes.h"
14 #include "base/files/file_path.h"
15 #include "base/files/memory_mapped_file.h"
16 #include "base/logging.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string16.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/sys_byteorder.h"
22 #include "base/values.h"
23 #include "chrome/browser/policy/policy_load_status.h"
24 #include "components/policy/core/common/registry_dict_win.h"
25
26 namespace policy {
27 namespace preg_parser {
28
29 const char kPRegFileHeader[8] =
30 { 'P', 'R', 'e', 'g', '\x01', '\x00', '\x00', '\x00' };
31
32 // Maximum PReg file size we're willing to accept.
33 const int64 kMaxPRegFileSize = 1024 * 1024 * 16;
34
35 // Constants for PReg file delimiters.
36 const char16 kDelimBracketOpen = L'[';
37 const char16 kDelimBracketClose = L']';
38 const char16 kDelimSemicolon = L';';
39
40 // Registry path separator.
41 const char16 kRegistryPathSeparator[] = L"\\";
42
43 // Magic strings for the PReg value field to trigger special actions.
44 const char kActionTriggerPrefix[] = "**";
45 const char kActionTriggerDeleteValues[] = "deletevalues";
46 const char kActionTriggerDel[] = "del.";
47 const char kActionTriggerDelVals[] = "delvals";
48 const char kActionTriggerDeleteKeys[] = "deletekeys";
49 const char kActionTriggerSecureKey[] = "securekey";
50 const char kActionTriggerSoft[] = "soft";
51
52 // Returns the character at |cursor| and increments it, unless the end is here
53 // in which case -1 is returned.
54 int NextChar(const uint8** cursor, const uint8* end) {
55 // Only read the character if a full char16 is available.
56 if (*cursor + sizeof(char16) > end)
57 return -1;
58
59 int result = **cursor | (*(*cursor + 1) << 8);
60 *cursor += sizeof(char16);
61 return result;
62 }
63
64 // Reads a fixed-size field from a PReg file.
65 bool ReadFieldBinary(const uint8** cursor,
66 const uint8* end,
67 uint32 size,
68 uint8* data) {
69 if (size == 0)
70 return true;
71
72 const uint8* field_end = *cursor + size;
73 if (field_end <= *cursor || field_end > end)
74 return false;
75 std::copy(*cursor, field_end, data);
76 *cursor = field_end;
77 return true;
78 }
79
80 bool ReadField32(const uint8** cursor, const uint8* end, uint32* data) {
81 uint32 value = 0;
82 if (!ReadFieldBinary(cursor, end, sizeof(uint32),
83 reinterpret_cast<uint8*>(&value))) {
84 return false;
85 }
86 *data = base::ByteSwapToLE32(value);
87 return true;
88 }
89
90 // Reads a string field from a file.
91 bool ReadFieldString(const uint8** cursor, const uint8* end, string16* str) {
92 int current = -1;
93 while ((current = NextChar(cursor, end)) > 0x0000)
94 *str += current;
95
96 return current == L'\0';
97 }
98
99 std::string DecodePRegStringValue(const std::vector<uint8>& data) {
100 size_t len = data.size() / sizeof(char16);
101 if (len <= 0)
102 return std::string();
103
104 const char16* chars = reinterpret_cast<const char16*>(vector_as_array(&data));
105 string16 result;
106 std::transform(chars, chars + len - 1, std::back_inserter(result),
107 std::ptr_fun(base::ByteSwapToLE16));
108 return UTF16ToUTF8(result);
109 }
110
111 // Decodes a value from a PReg file given as a uint8 vector.
112 bool DecodePRegValue(uint32 type,
113 const std::vector<uint8>& data,
114 scoped_ptr<base::Value>* value) {
115 switch (type) {
116 case REG_SZ:
117 case REG_EXPAND_SZ:
118 value->reset(base::Value::CreateStringValue(DecodePRegStringValue(data)));
119 return true;
120 case REG_DWORD_LITTLE_ENDIAN:
121 case REG_DWORD_BIG_ENDIAN:
122 if (data.size() == sizeof(uint32)) {
123 uint32 val = *reinterpret_cast<const uint32*>(vector_as_array(&data));
124 if (type == REG_DWORD_BIG_ENDIAN)
125 val = base::NetToHost32(val);
126 else
127 val = base::ByteSwapToLE32(val);
128 value->reset(base::Value::CreateIntegerValue(static_cast<int>(val)));
129 return true;
130 } else {
131 LOG(ERROR) << "Bad data size " << data.size();
132 }
133 break;
134 case REG_NONE:
135 case REG_LINK:
136 case REG_MULTI_SZ:
137 case REG_RESOURCE_LIST:
138 case REG_FULL_RESOURCE_DESCRIPTOR:
139 case REG_RESOURCE_REQUIREMENTS_LIST:
140 case REG_QWORD_LITTLE_ENDIAN:
141 default:
142 LOG(ERROR) << "Unsupported registry data type " << type;
143 }
144
145 return false;
146 }
147
148 // Adds the record data passed via parameters to |dict| in case the data is
149 // relevant policy for Chromium.
150 void HandleRecord(const string16& key_name,
151 const string16& value,
152 uint32 type,
153 const std::vector<uint8>& data,
154 RegistryDict* dict) {
155 // Locate/create the dictionary to place the value in.
156 std::vector<string16> path;
157
158 Tokenize(key_name, kRegistryPathSeparator, &path);
159 for (std::vector<string16>::const_iterator entry(path.begin());
160 entry != path.end(); ++entry) {
161 if (entry->empty())
162 continue;
163 const std::string name = UTF16ToUTF8(*entry);
164 RegistryDict* subdict = dict->GetKey(name);
165 if (!subdict) {
166 subdict = new RegistryDict();
167 dict->SetKey(name, make_scoped_ptr(subdict));
168 }
169 dict = subdict;
170 }
171
172 if (value.empty())
173 return;
174
175 std::string value_name(UTF16ToUTF8(value));
176 if (!StartsWithASCII(value_name, kActionTriggerPrefix, true)) {
177 scoped_ptr<base::Value> value;
178 if (DecodePRegValue(type, data, &value))
179 dict->SetValue(value_name, value.Pass());
180 return;
181 }
182
183 std::string action_trigger(StringToLowerASCII(value_name.substr(
184 arraysize(kActionTriggerPrefix) - 1)));
185 if (action_trigger == kActionTriggerDeleteValues) {
186 std::vector<std::string> values;
187 Tokenize(DecodePRegStringValue(data), ";", &values);
188 for (std::vector<std::string>::const_iterator value(values.begin());
189 value != values.end(); ++value) {
190 dict->RemoveValue(*value);
191 }
192 } else if (StartsWithASCII(action_trigger, kActionTriggerDeleteKeys, true)) {
193 std::vector<std::string> keys;
194 Tokenize(DecodePRegStringValue(data), ";", &keys);
195 for (std::vector<std::string>::const_iterator key(keys.begin());
196 key != keys.end(); ++key) {
197 dict->RemoveKey(*key);
198 }
199 } else if (StartsWithASCII(action_trigger, kActionTriggerDel, true)) {
200 dict->RemoveValue(
201 value_name.substr(arraysize(kActionTriggerPrefix) - 1 +
202 arraysize(kActionTriggerDel) - 1));
203 } else if (StartsWithASCII(action_trigger, kActionTriggerDelVals, true)) {
204 // Delete all values.
205 dict->ClearValues();
206 } else if (StartsWithASCII(action_trigger, kActionTriggerSecureKey, true) ||
207 StartsWithASCII(action_trigger, kActionTriggerSoft, true)) {
208 // Doesn't affect values.
209 } else {
210 LOG(ERROR) << "Bad action trigger " << value_name;
211 }
212 }
213
214 bool ReadFile(const base::FilePath& file_path,
215 const string16& root,
216 RegistryDict* dict,
217 PolicyLoadStatusSample* status) {
218 base::MemoryMappedFile mapped_file;
219 if (!mapped_file.Initialize(file_path) || !mapped_file.IsValid()) {
220 PLOG(ERROR) << "Failed to map " << file_path.value();
221 status->Add(POLICY_LOAD_STATUS_READ_ERROR);
222 return false;
223 }
224
225 if (mapped_file.length() > kMaxPRegFileSize) {
226 LOG(ERROR) << "PReg file " << file_path.value() << " too large: "
227 << mapped_file.length();
228 status->Add(POLICY_LOAD_STATUS_TOO_BIG);
229 return false;
230 }
231
232 // Check the header.
233 const int kHeaderSize = arraysize(kPRegFileHeader);
234 if (mapped_file.length() < kHeaderSize ||
235 memcmp(kPRegFileHeader, mapped_file.data(), kHeaderSize) != 0) {
236 LOG(ERROR) << "Bad policy file " << file_path.value();
237 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR);
238 return false;
239 }
240
241 // Parse file contents, which is UCS-2 and little-endian. The latter I
242 // couldn't find documentation on, but the example I saw were all
243 // little-endian. It'd be interesting to check on big-endian hardware.
244 const uint8* cursor = mapped_file.data() + kHeaderSize;
245 const uint8* end = mapped_file.data() + mapped_file.length();
246 while (true) {
247 if (cursor == end)
248 return true;
249
250 if (NextChar(&cursor, end) != kDelimBracketOpen)
251 break;
252
253 // Read the record fields.
254 string16 key_name;
255 string16 value;
256 uint32 type = 0;
257 uint32 size = 0;
258 std::vector<uint8> data;
259
260 if (!ReadFieldString(&cursor, end, &key_name))
261 break;
262
263 int current = NextChar(&cursor, end);
264 if (current == kDelimSemicolon) {
265 if (!ReadFieldString(&cursor, end, &value))
266 break;
267 current = NextChar(&cursor, end);
268 }
269
270 if (current == kDelimSemicolon) {
271 if (!ReadField32(&cursor, end, &type))
272 break;
273 current = NextChar(&cursor, end);
274 }
275
276 if (current == kDelimSemicolon) {
277 if (!ReadField32(&cursor, end, &size))
278 break;
279 current = NextChar(&cursor, end);
280 }
281
282 if (current == kDelimSemicolon) {
283 if (size > kMaxPRegFileSize)
284 break;
285 data.resize(size);
286 if (!ReadFieldBinary(&cursor, end, size, vector_as_array(&data)))
287 break;
288 current = NextChar(&cursor, end);
289 }
290
291 if (current != kDelimBracketClose)
292 break;
293
294 // Process the record if it is within the |root| subtree.
295 if (StartsWith(key_name, root, false))
296 HandleRecord(key_name.substr(root.size()), value, type, data, dict);
297 }
298
299 LOG(ERROR) << "Error parsing " << file_path.value() << " at offset "
300 << reinterpret_cast<const uint8*>(cursor - 1) - mapped_file.data();
301 status->Add(POLICY_LOAD_STATUS_PARSE_ERROR);
302 return false;
303 }
304
305 } // namespace preg_parser
306 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/preg_parser_win.h ('k') | chrome/browser/policy/preg_parser_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698