1 // Copyright (c) 2011 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.
7 #pragma comment(lib, "wtsapi32.lib")
9 #include "chrome/browser/policy/policy_path_parser.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/registry.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "policy/policy_constants.h"
19 // Checks if the registry key exists in the given hive and expands any
20 // variables in the string.
21 bool LoadUserDataDirPolicyFromRegistry(HKEY hive
,
22 const std::wstring
& key_name
,
23 base::FilePath
* user_data_dir
) {
26 base::win::RegKey
policy_key(hive
,
27 policy::kRegistryChromePolicyKey
,
29 if (policy_key
.ReadValue(key_name
.c_str(), &value
) == ERROR_SUCCESS
) {
31 base::FilePath(policy::path_parser::ExpandPathVariables(value
));
37 const WCHAR
* kMachineNamePolicyVarName
= L
"${machine_name}";
38 const WCHAR
* kUserNamePolicyVarName
= L
"${user_name}";
39 const WCHAR
* kWinDocumentsFolderVarName
= L
"${documents}";
40 const WCHAR
* kWinLocalAppDataFolderVarName
= L
"${local_app_data}";
41 const WCHAR
* kWinRoamingAppDataFolderVarName
= L
"${roaming_app_data}";
42 const WCHAR
* kWinProfileFolderVarName
= L
"${profile}";
43 const WCHAR
* kWinProgramDataFolderVarName
= L
"${global_app_data}";
44 const WCHAR
* kWinProgramFilesFolderVarName
= L
"${program_files}";
45 const WCHAR
* kWinWindowsFolderVarName
= L
"${windows}";
46 const WCHAR
* kWinClientName
= L
"${client_name}";
48 struct WinFolderNamesToCSIDLMapping
{
53 // Mapping from variable names to Windows CSIDL ids.
54 const WinFolderNamesToCSIDLMapping win_folder_mapping
[] = {
55 { kWinWindowsFolderVarName
, CSIDL_WINDOWS
},
56 { kWinProgramFilesFolderVarName
, CSIDL_PROGRAM_FILES
},
57 { kWinProgramDataFolderVarName
, CSIDL_COMMON_APPDATA
},
58 { kWinProfileFolderVarName
, CSIDL_PROFILE
},
59 { kWinLocalAppDataFolderVarName
, CSIDL_LOCAL_APPDATA
},
60 { kWinRoamingAppDataFolderVarName
, CSIDL_APPDATA
},
61 { kWinDocumentsFolderVarName
, CSIDL_PERSONAL
}
68 namespace path_parser
{
70 // Replaces all variable occurances in the policy string with the respective
71 // system settings values.
72 base::FilePath::StringType
ExpandPathVariables(
73 const base::FilePath::StringType
& untranslated_string
) {
74 base::FilePath::StringType
result(untranslated_string
);
75 if (result
.length() == 0)
77 // Sanitize quotes in case of any around the whole string.
78 if (result
.length() > 1 &&
79 ((result
[0] == L
'"' && result
[result
.length() - 1] == L
'"') ||
80 (result
[0] == L
'\'' && result
[result
.length() - 1] == L
'\''))) {
81 // Strip first and last char which should be matching quotes now.
82 result
= result
.substr(1, result
.length() - 2);
84 // First translate all path variables we recognize.
85 for (int i
= 0; i
< arraysize(win_folder_mapping
); ++i
) {
86 size_t position
= result
.find(win_folder_mapping
[i
].name
);
87 if (position
!= std::wstring::npos
) {
89 ::SHGetSpecialFolderPath(0, path
, win_folder_mapping
[i
].id
, false);
90 std::wstring
path_string(path
);
91 result
.replace(position
, wcslen(win_folder_mapping
[i
].name
), path_string
);
94 // Next translate other windows specific variables.
95 size_t position
= result
.find(kUserNamePolicyVarName
);
96 if (position
!= std::wstring::npos
) {
97 DWORD return_length
= 0;
98 ::GetUserName(NULL
, &return_length
);
99 if (return_length
!= 0) {
100 scoped_ptr
<WCHAR
[]> username(new WCHAR
[return_length
]);
101 ::GetUserName(username
.get(), &return_length
);
102 std::wstring
username_string(username
.get());
103 result
.replace(position
, wcslen(kUserNamePolicyVarName
), username_string
);
106 position
= result
.find(kMachineNamePolicyVarName
);
107 if (position
!= std::wstring::npos
) {
108 DWORD return_length
= 0;
109 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname
, NULL
, &return_length
);
110 if (return_length
!= 0) {
111 scoped_ptr
<WCHAR
[]> machinename(new WCHAR
[return_length
]);
112 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname
,
113 machinename
.get(), &return_length
);
114 std::wstring
machinename_string(machinename
.get());
116 position
, wcslen(kMachineNamePolicyVarName
), machinename_string
);
119 position
= result
.find(kWinClientName
);
120 if (position
!= std::wstring::npos
) {
121 LPWSTR buffer
= NULL
;
122 DWORD buffer_length
= 0;
123 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER
, WTS_CURRENT_SESSION
,
125 &buffer
, &buffer_length
)) {
126 std::wstring
clientname_string(buffer
);
127 result
.replace(position
, wcslen(kWinClientName
), clientname_string
);
128 ::WTSFreeMemory(buffer
);
135 void CheckUserDataDirPolicy(base::FilePath
* user_data_dir
) {
136 DCHECK(user_data_dir
);
138 // Policy from the HKLM hive has precedence over HKCU so if we have one here
139 // we don't have to try to load HKCU.
140 std::wstring
key_name(base::ASCIIToWide(policy::key::kUserDataDir
));
141 if (!LoadUserDataDirPolicyFromRegistry(HKEY_LOCAL_MACHINE
, key_name
,
143 LoadUserDataDirPolicyFromRegistry(
144 HKEY_CURRENT_USER
, key_name
, user_data_dir
);
148 } // namespace path_parser
150 } // namespace policy