| 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 |