OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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_path_parser.h" | 5 #include "chrome/install_static/policy_path_parser.h" |
6 | 6 |
| 7 #include <assert.h> |
7 #include <shlobj.h> | 8 #include <shlobj.h> |
8 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <stdlib.h> |
9 #include <wtsapi32.h> | 11 #include <wtsapi32.h> |
10 | 12 |
11 #include <memory> | 13 #include <memory> |
12 | 14 |
13 #include "base/macros.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "base/win/registry.h" | |
16 #include "chrome/common/chrome_switches.h" | |
17 #include "components/policy/policy_constants.h" | |
18 | |
19 namespace { | 15 namespace { |
20 | 16 |
21 // Checks if the key exists in the given hive and expands any string variables. | |
22 bool LoadUserDataDirPolicyFromRegistry(HKEY hive, | |
23 const char* key_name_str, | |
24 base::FilePath* dir) { | |
25 base::string16 value; | |
26 base::string16 key_name(base::ASCIIToUTF16(key_name_str)); | |
27 base::win::RegKey key(hive, policy::kRegistryChromePolicyKey, KEY_READ); | |
28 if (key.ReadValue(key_name.c_str(), &value) == ERROR_SUCCESS) { | |
29 *dir = base::FilePath(policy::path_parser::ExpandPathVariables(value)); | |
30 return true; | |
31 } | |
32 return false; | |
33 } | |
34 | |
35 const WCHAR* kMachineNamePolicyVarName = L"${machine_name}"; | 17 const WCHAR* kMachineNamePolicyVarName = L"${machine_name}"; |
36 const WCHAR* kUserNamePolicyVarName = L"${user_name}"; | 18 const WCHAR* kUserNamePolicyVarName = L"${user_name}"; |
37 const WCHAR* kWinDocumentsFolderVarName = L"${documents}"; | 19 const WCHAR* kWinDocumentsFolderVarName = L"${documents}"; |
38 const WCHAR* kWinLocalAppDataFolderVarName = L"${local_app_data}"; | 20 const WCHAR* kWinLocalAppDataFolderVarName = L"${local_app_data}"; |
39 const WCHAR* kWinRoamingAppDataFolderVarName = L"${roaming_app_data}"; | 21 const WCHAR* kWinRoamingAppDataFolderVarName = L"${roaming_app_data}"; |
40 const WCHAR* kWinProfileFolderVarName = L"${profile}"; | 22 const WCHAR* kWinProfileFolderVarName = L"${profile}"; |
41 const WCHAR* kWinProgramDataFolderVarName = L"${global_app_data}"; | 23 const WCHAR* kWinProgramDataFolderVarName = L"${global_app_data}"; |
42 const WCHAR* kWinProgramFilesFolderVarName = L"${program_files}"; | 24 const WCHAR* kWinProgramFilesFolderVarName = L"${program_files}"; |
43 const WCHAR* kWinWindowsFolderVarName = L"${windows}"; | 25 const WCHAR* kWinWindowsFolderVarName = L"${windows}"; |
44 const WCHAR* kWinClientName = L"${client_name}"; | 26 const WCHAR* kWinClientName = L"${client_name}"; |
45 const WCHAR* kWinSessionName = L"${session_name}"; | 27 const WCHAR* kWinSessionName = L"${session_name}"; |
46 | 28 |
47 struct WinFolderNamesToCSIDLMapping { | 29 struct WinFolderNamesToCSIDLMapping { |
48 const WCHAR* name; | 30 const WCHAR* name; |
49 int id; | 31 int id; |
50 }; | 32 }; |
51 | 33 |
52 // Mapping from variable names to Windows CSIDL ids. | 34 // Mapping from variable names to Windows CSIDL ids. |
53 const WinFolderNamesToCSIDLMapping win_folder_mapping[] = { | 35 const WinFolderNamesToCSIDLMapping kWinFolderMapping[] = { |
54 { kWinWindowsFolderVarName, CSIDL_WINDOWS}, | 36 { kWinWindowsFolderVarName, CSIDL_WINDOWS}, |
55 { kWinProgramFilesFolderVarName, CSIDL_PROGRAM_FILES}, | 37 { kWinProgramFilesFolderVarName, CSIDL_PROGRAM_FILES}, |
56 { kWinProgramDataFolderVarName, CSIDL_COMMON_APPDATA}, | 38 { kWinProgramDataFolderVarName, CSIDL_COMMON_APPDATA}, |
57 { kWinProfileFolderVarName, CSIDL_PROFILE}, | 39 { kWinProfileFolderVarName, CSIDL_PROFILE}, |
58 { kWinLocalAppDataFolderVarName, CSIDL_LOCAL_APPDATA}, | 40 { kWinLocalAppDataFolderVarName, CSIDL_LOCAL_APPDATA}, |
59 { kWinRoamingAppDataFolderVarName, CSIDL_APPDATA}, | 41 { kWinRoamingAppDataFolderVarName, CSIDL_APPDATA}, |
60 { kWinDocumentsFolderVarName, CSIDL_PERSONAL} | 42 { kWinDocumentsFolderVarName, CSIDL_PERSONAL} |
61 }; | 43 }; |
62 | 44 |
| 45 template <class FunctionType> |
| 46 struct ScopedFunctionHelper { |
| 47 ScopedFunctionHelper(const wchar_t* library_name, const char* function_name) { |
| 48 library_ = LoadLibrary(library_name); |
| 49 assert(library_); |
| 50 if (library_) { |
| 51 // Strip off any leading :: that may have come from stringifying the |
| 52 // function's name. |
| 53 if (function_name[0] == ':' && function_name[1] == ':' && |
| 54 function_name[2] && function_name[2] != ':') { |
| 55 function_name += 2; |
| 56 } |
| 57 function_ = reinterpret_cast<FunctionType *>( |
| 58 GetProcAddress(library_, function_name)); |
| 59 assert(function_); |
| 60 } |
| 61 } |
| 62 |
| 63 ~ScopedFunctionHelper() { |
| 64 if (library_) |
| 65 FreeLibrary(library_); |
| 66 } |
| 67 |
| 68 template <class... Args> auto operator()(Args... a) { |
| 69 return function_(a...); |
| 70 } |
| 71 |
| 72 private: |
| 73 HMODULE library_; |
| 74 FunctionType* function_; |
| 75 }; |
| 76 |
| 77 #define SCOPED_LOAD_FUNCTION(library, function) \ |
| 78 ScopedFunctionHelper<decltype(function)>(library, #function) |
| 79 |
63 } // namespace | 80 } // namespace |
64 | 81 |
65 namespace policy { | 82 namespace install_static { |
66 | |
67 namespace path_parser { | |
68 | 83 |
69 // Replaces all variable occurances in the policy string with the respective | 84 // Replaces all variable occurances in the policy string with the respective |
70 // system settings values. | 85 // system settings values. |
71 base::FilePath::StringType ExpandPathVariables( | 86 // Note that this uses GetProcAddress to load DLLs that cannot be loaded before |
72 const base::FilePath::StringType& untranslated_string) { | 87 // the blacklist in the DllMain of chrome_elf has been applied. This function |
73 base::FilePath::StringType result(untranslated_string); | 88 // should only be used after DllMain() has run. |
| 89 std::wstring ExpandPathVariables( |
| 90 const std::wstring& untranslated_string) { |
| 91 std::wstring result(untranslated_string); |
74 if (result.length() == 0) | 92 if (result.length() == 0) |
75 return result; | 93 return result; |
76 // Sanitize quotes in case of any around the whole string. | 94 // Sanitize quotes in case of any around the whole string. |
77 if (result.length() > 1 && | 95 if (result.length() > 1 && |
78 ((result.front() == L'"' && result.back() == L'"') || | 96 ((result.front() == L'"' && result.back() == L'"') || |
79 (result.front() == L'\'' && result.back() == L'\''))) { | 97 (result.front() == L'\'' && result.back() == L'\''))) { |
80 // Strip first and last char which should be matching quotes now. | 98 // Strip first and last char which should be matching quotes now. |
81 result = result.substr(1, result.length() - 2); | 99 result.pop_back(); |
| 100 result.erase(0, 1); |
82 } | 101 } |
| 102 auto sh_get_special_folder_path = |
| 103 SCOPED_LOAD_FUNCTION(L"shell32.dll", ::SHGetSpecialFolderPathW); |
83 // First translate all path variables we recognize. | 104 // First translate all path variables we recognize. |
84 for (size_t i = 0; i < arraysize(win_folder_mapping); ++i) { | 105 for (size_t i = 0; i < _countof(kWinFolderMapping); ++i) { |
85 size_t position = result.find(win_folder_mapping[i].name); | 106 size_t position = result.find(kWinFolderMapping[i].name); |
86 if (position != std::wstring::npos) { | 107 if (position != std::wstring::npos) { |
87 WCHAR path[MAX_PATH]; | 108 WCHAR path[MAX_PATH]; |
88 ::SHGetSpecialFolderPath(0, path, win_folder_mapping[i].id, false); | 109 sh_get_special_folder_path(nullptr, path, kWinFolderMapping[i].id, false); |
89 std::wstring path_string(path); | 110 std::wstring path_string(path); |
90 result.replace(position, wcslen(win_folder_mapping[i].name), path_string); | 111 result.replace(position, wcslen(kWinFolderMapping[i].name), path_string); |
91 } | 112 } |
92 } | 113 } |
93 // Next translate other windows specific variables. | 114 // Next translate other windows specific variables. |
| 115 auto get_user_name = SCOPED_LOAD_FUNCTION(L"advapi32.dll", ::GetUserNameW); |
94 size_t position = result.find(kUserNamePolicyVarName); | 116 size_t position = result.find(kUserNamePolicyVarName); |
95 if (position != std::wstring::npos) { | 117 if (position != std::wstring::npos) { |
96 DWORD return_length = 0; | 118 DWORD return_length = 0; |
97 ::GetUserName(NULL, &return_length); | 119 get_user_name(nullptr, &return_length); |
98 if (return_length != 0) { | 120 if (return_length != 0) { |
99 std::unique_ptr<WCHAR[]> username(new WCHAR[return_length]); | 121 std::unique_ptr<WCHAR[]> username(new WCHAR[return_length]); |
100 ::GetUserName(username.get(), &return_length); | 122 get_user_name(username.get(), &return_length); |
101 std::wstring username_string(username.get()); | 123 std::wstring username_string(username.get()); |
102 result.replace(position, wcslen(kUserNamePolicyVarName), username_string); | 124 result.replace(position, wcslen(kUserNamePolicyVarName), username_string); |
103 } | 125 } |
104 } | 126 } |
105 position = result.find(kMachineNamePolicyVarName); | 127 position = result.find(kMachineNamePolicyVarName); |
106 if (position != std::wstring::npos) { | 128 if (position != std::wstring::npos) { |
107 DWORD return_length = 0; | 129 DWORD return_length = 0; |
108 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname, NULL, &return_length); | 130 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname, NULL, &return_length); |
109 if (return_length != 0) { | 131 if (return_length != 0) { |
110 std::unique_ptr<WCHAR[]> machinename(new WCHAR[return_length]); | 132 std::unique_ptr<WCHAR[]> machinename(new WCHAR[return_length]); |
111 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname, | 133 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname, |
112 machinename.get(), &return_length); | 134 machinename.get(), &return_length); |
113 std::wstring machinename_string(machinename.get()); | 135 std::wstring machinename_string(machinename.get()); |
114 result.replace( | 136 result.replace( |
115 position, wcslen(kMachineNamePolicyVarName), machinename_string); | 137 position, wcslen(kMachineNamePolicyVarName), machinename_string); |
116 } | 138 } |
117 } | 139 } |
| 140 auto wts_query_session_information = |
| 141 SCOPED_LOAD_FUNCTION(L"wtsapi32.dll", ::WTSQuerySessionInformationW); |
| 142 auto wts_free_memory = SCOPED_LOAD_FUNCTION(L"wtsapi32.dll", ::WTSFreeMemory); |
118 position = result.find(kWinClientName); | 143 position = result.find(kWinClientName); |
119 if (position != std::wstring::npos) { | 144 if (position != std::wstring::npos) { |
120 LPWSTR buffer = NULL; | 145 LPWSTR buffer = NULL; |
121 DWORD buffer_length = 0; | 146 DWORD buffer_length = 0; |
122 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION, | 147 if (wts_query_session_information(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION, |
123 WTSClientName, | 148 WTSClientName, &buffer, &buffer_length)) { |
124 &buffer, &buffer_length)) { | |
125 std::wstring clientname_string(buffer); | 149 std::wstring clientname_string(buffer); |
126 result.replace(position, wcslen(kWinClientName), clientname_string); | 150 result.replace(position, wcslen(kWinClientName), clientname_string); |
127 ::WTSFreeMemory(buffer); | 151 wts_free_memory(buffer); |
128 } | 152 } |
129 } | 153 } |
130 position = result.find(kWinSessionName); | 154 position = result.find(kWinSessionName); |
131 if (position != std::wstring::npos) { | 155 if (position != std::wstring::npos) { |
132 LPWSTR buffer = NULL; | 156 LPWSTR buffer = NULL; |
133 DWORD buffer_length = 0; | 157 DWORD buffer_length = 0; |
134 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION, | 158 if (wts_query_session_information(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION, |
135 WTSWinStationName, | 159 WTSWinStationName, &buffer, |
136 &buffer, &buffer_length)) { | 160 &buffer_length)) { |
137 std::wstring sessionname_string(buffer); | 161 std::wstring sessionname_string(buffer); |
138 result.replace(position, wcslen(kWinSessionName), sessionname_string); | 162 result.replace(position, wcslen(kWinSessionName), sessionname_string); |
139 ::WTSFreeMemory(buffer); | 163 wts_free_memory(buffer); |
140 } | 164 } |
141 } | 165 } |
142 // TODO(pastarmovj): Consider reorganizing this code once there are even more | 166 // TODO(pastarmovj): Consider reorganizing this code once there are even more |
143 // variables to be supported. The search for the var and its replacement can | 167 // variables to be supported. The search for the var and its replacement can |
144 // be extracted as common functionality. | 168 // be extracted as common functionality. |
145 | 169 |
146 return result; | 170 return result; |
147 } | 171 } |
148 | 172 |
149 void CheckUserDataDirPolicy(base::FilePath* user_data_dir) { | 173 } // namespace install_static |
150 DCHECK(user_data_dir); | |
151 // Policy from the HKLM hive has precedence over HKCU. | |
152 if (!LoadUserDataDirPolicyFromRegistry(HKEY_LOCAL_MACHINE, key::kUserDataDir, | |
153 user_data_dir)) { | |
154 LoadUserDataDirPolicyFromRegistry(HKEY_CURRENT_USER, key::kUserDataDir, | |
155 user_data_dir); | |
156 } | |
157 } | |
158 | |
159 void CheckDiskCacheDirPolicy(base::FilePath* disk_cache_dir) { | |
160 DCHECK(disk_cache_dir); | |
161 if (!LoadUserDataDirPolicyFromRegistry(HKEY_LOCAL_MACHINE, key::kDiskCacheDir, | |
162 disk_cache_dir)) { | |
163 LoadUserDataDirPolicyFromRegistry(HKEY_CURRENT_USER, key::kDiskCacheDir, | |
164 disk_cache_dir); | |
165 } | |
166 } | |
167 | |
168 } // namespace path_parser | |
169 | |
170 } // namespace policy | |
OLD | NEW |