forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpolicy_path_parser.cc
186 lines (169 loc) · 7.14 KB
/
policy_path_parser.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/install_static/policy_path_parser.h"
#include <assert.h>
#include <shlobj.h>
#include <stddef.h>
#include <stdlib.h>
#include <wtsapi32.h>
#include <memory>
namespace {
constexpr WCHAR kMachineNamePolicyVarName[] = L"${machine_name}";
constexpr WCHAR kUserNamePolicyVarName[] = L"${user_name}";
constexpr WCHAR kWinDocumentsFolderVarName[] = L"${documents}";
constexpr WCHAR kWinLocalAppDataFolderVarName[] = L"${local_app_data}";
constexpr WCHAR kWinRoamingAppDataFolderVarName[] = L"${roaming_app_data}";
constexpr WCHAR kWinProfileFolderVarName[] = L"${profile}";
constexpr WCHAR kWinProgramDataFolderVarName[] = L"${global_app_data}";
constexpr WCHAR kWinProgramFilesFolderVarName[] = L"${program_files}";
constexpr WCHAR kWinWindowsFolderVarName[] = L"${windows}";
constexpr WCHAR kWinClientName[] = L"${client_name}";
constexpr WCHAR kWinSessionName[] = L"${session_name}";
struct WinFolderNamesToCSIDLMapping {
const WCHAR* name;
int id;
};
// Mapping from variable names to Windows CSIDL ids.
constexpr WinFolderNamesToCSIDLMapping kWinFolderMapping[] = {
{kWinWindowsFolderVarName, CSIDL_WINDOWS},
{kWinProgramFilesFolderVarName, CSIDL_PROGRAM_FILES},
{kWinProgramDataFolderVarName, CSIDL_COMMON_APPDATA},
{kWinProfileFolderVarName, CSIDL_PROFILE},
{kWinLocalAppDataFolderVarName, CSIDL_LOCAL_APPDATA},
{kWinRoamingAppDataFolderVarName, CSIDL_APPDATA},
{kWinDocumentsFolderVarName, CSIDL_PERSONAL}};
template <class FunctionType>
struct ScopedFunctionHelper {
ScopedFunctionHelper(const wchar_t* library_name, const char* function_name) {
library_ = LoadLibrary(library_name);
assert(library_);
if (library_) {
// Strip off any leading :: that may have come from stringifying the
// function's name.
if (function_name[0] == ':' && function_name[1] == ':' &&
function_name[2] && function_name[2] != ':') {
function_name += 2;
}
function_ = reinterpret_cast<FunctionType*>(
GetProcAddress(library_, function_name));
assert(function_);
}
}
~ScopedFunctionHelper() {
if (library_)
FreeLibrary(library_);
}
template <class... Args>
auto operator()(Args... a) {
return function_(a...);
}
private:
HMODULE library_;
FunctionType* function_;
};
#define SCOPED_LOAD_FUNCTION(library, function) \
ScopedFunctionHelper<decltype(function)>(library, #function)
} // namespace
namespace install_static {
// Replaces all variable occurrences in the policy string with the respective
// system settings values.
// Note that this uses GetProcAddress to load DLLs that cannot be loaded before
// the blacklist in the DllMain of chrome_elf has been applied. This function
// should only be used after DllMain() has run.
std::wstring ExpandPathVariables(const std::wstring& untranslated_string) {
std::wstring result(untranslated_string);
if (result.length() == 0)
return result;
// Sanitize quotes in case of any around the whole string.
if (result.length() > 1 &&
((result.front() == L'"' && result.back() == L'"') ||
(result.front() == L'\'' && result.back() == L'\''))) {
// Strip first and last char which should be matching quotes now.
result.pop_back();
result.erase(0, 1);
}
auto sh_get_special_folder_path =
SCOPED_LOAD_FUNCTION(L"shell32.dll", ::SHGetSpecialFolderPathW);
// First translate all path variables we recognize.
for (size_t i = 0; i < _countof(kWinFolderMapping); ++i) {
size_t position = result.find(kWinFolderMapping[i].name);
if (position != std::wstring::npos) {
size_t variable_length = wcslen(kWinFolderMapping[i].name);
WCHAR path[MAX_PATH];
if (!sh_get_special_folder_path(nullptr, path, kWinFolderMapping[i].id,
false)) {
path[0] = 0;
}
std::wstring path_string(path);
// Remove a trailing slash if there is any but also only if the rest of
// the string contains one right after to avoid ending in a drive only
// value situation. This usually won't happen but if the value of this
// special folder is the root of a drive it will be presented as D:\.
if (!path_string.empty() && path_string.back() == L'\\' &&
result.length() > position + variable_length &&
result[position + variable_length] == L'\\') {
path_string.pop_back();
}
result.replace(position, variable_length, path_string);
}
}
// Next translate other windows specific variables.
auto get_user_name = SCOPED_LOAD_FUNCTION(L"advapi32.dll", ::GetUserNameW);
size_t position = result.find(kUserNamePolicyVarName);
if (position != std::wstring::npos) {
DWORD return_length = 0;
get_user_name(nullptr, &return_length);
if (return_length != 0) {
std::unique_ptr<WCHAR[]> username(new WCHAR[return_length]);
get_user_name(username.get(), &return_length);
std::wstring username_string(username.get());
result.replace(position, wcslen(kUserNamePolicyVarName), username_string);
}
}
position = result.find(kMachineNamePolicyVarName);
if (position != std::wstring::npos) {
DWORD return_length = 0;
::GetComputerNameEx(ComputerNamePhysicalDnsHostname, nullptr,
&return_length);
if (return_length != 0) {
std::unique_ptr<WCHAR[]> machinename(new WCHAR[return_length]);
::GetComputerNameEx(ComputerNamePhysicalDnsHostname, machinename.get(),
&return_length);
std::wstring machinename_string(machinename.get());
result.replace(position, wcslen(kMachineNamePolicyVarName),
machinename_string);
}
}
auto wts_query_session_information =
SCOPED_LOAD_FUNCTION(L"wtsapi32.dll", ::WTSQuerySessionInformationW);
auto wts_free_memory = SCOPED_LOAD_FUNCTION(L"wtsapi32.dll", ::WTSFreeMemory);
position = result.find(kWinClientName);
if (position != std::wstring::npos) {
LPWSTR buffer = nullptr;
DWORD buffer_length = 0;
if (wts_query_session_information(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION,
WTSClientName, &buffer, &buffer_length)) {
std::wstring clientname_string(buffer);
result.replace(position, wcslen(kWinClientName), clientname_string);
wts_free_memory(buffer);
}
}
position = result.find(kWinSessionName);
if (position != std::wstring::npos) {
LPWSTR buffer = nullptr;
DWORD buffer_length = 0;
if (wts_query_session_information(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION,
WTSWinStationName, &buffer,
&buffer_length)) {
std::wstring sessionname_string(buffer);
result.replace(position, wcslen(kWinSessionName), sessionname_string);
wts_free_memory(buffer);
}
}
// TODO(pastarmovj): Consider reorganizing this code once there are even more
// variables to be supported. The search for the var and its replacement can
// be extracted as common functionality.
return result;
}
} // namespace install_static