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 187 188 189 190 191
|
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#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
|