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 key exists in the given hive and expands any string variables.
20 bool LoadUserDataDirPolicyFromRegistry(HKEY hive
, base::FilePath
* dir
) {
22 base::string16
key_name(base::ASCIIToUTF16(policy::key::kUserDataDir
));
23 base::win::RegKey
key(hive
, policy::kRegistryChromePolicyKey
, KEY_READ
);
24 if (key
.ReadValue(key_name
.c_str(), &value
) == ERROR_SUCCESS
) {
25 *dir
= base::FilePath(policy::path_parser::ExpandPathVariables(value
));
31 const WCHAR
* kMachineNamePolicyVarName
= L
"${machine_name}";
32 const WCHAR
* kUserNamePolicyVarName
= L
"${user_name}";
33 const WCHAR
* kWinDocumentsFolderVarName
= L
"${documents}";
34 const WCHAR
* kWinLocalAppDataFolderVarName
= L
"${local_app_data}";
35 const WCHAR
* kWinRoamingAppDataFolderVarName
= L
"${roaming_app_data}";
36 const WCHAR
* kWinProfileFolderVarName
= L
"${profile}";
37 const WCHAR
* kWinProgramDataFolderVarName
= L
"${global_app_data}";
38 const WCHAR
* kWinProgramFilesFolderVarName
= L
"${program_files}";
39 const WCHAR
* kWinWindowsFolderVarName
= L
"${windows}";
40 const WCHAR
* kWinClientName
= L
"${client_name}";
41 const WCHAR
* kWinSessionName
= L
"${session_name}";
43 struct WinFolderNamesToCSIDLMapping
{
48 // Mapping from variable names to Windows CSIDL ids.
49 const WinFolderNamesToCSIDLMapping win_folder_mapping
[] = {
50 { kWinWindowsFolderVarName
, CSIDL_WINDOWS
},
51 { kWinProgramFilesFolderVarName
, CSIDL_PROGRAM_FILES
},
52 { kWinProgramDataFolderVarName
, CSIDL_COMMON_APPDATA
},
53 { kWinProfileFolderVarName
, CSIDL_PROFILE
},
54 { kWinLocalAppDataFolderVarName
, CSIDL_LOCAL_APPDATA
},
55 { kWinRoamingAppDataFolderVarName
, CSIDL_APPDATA
},
56 { kWinDocumentsFolderVarName
, CSIDL_PERSONAL
}
63 namespace path_parser
{
65 // Replaces all variable occurances in the policy string with the respective
66 // system settings values.
67 base::FilePath::StringType
ExpandPathVariables(
68 const base::FilePath::StringType
& untranslated_string
) {
69 base::FilePath::StringType
result(untranslated_string
);
70 if (result
.length() == 0)
72 // Sanitize quotes in case of any around the whole string.
73 if (result
.length() > 1 &&
74 ((result
[0] == L
'"' && result
[result
.length() - 1] == L
'"') ||
75 (result
[0] == L
'\'' && result
[result
.length() - 1] == L
'\''))) {
76 // Strip first and last char which should be matching quotes now.
77 result
= result
.substr(1, result
.length() - 2);
79 // First translate all path variables we recognize.
80 for (int i
= 0; i
< arraysize(win_folder_mapping
); ++i
) {
81 size_t position
= result
.find(win_folder_mapping
[i
].name
);
82 if (position
!= std::wstring::npos
) {
84 ::SHGetSpecialFolderPath(0, path
, win_folder_mapping
[i
].id
, false);
85 std::wstring
path_string(path
);
86 result
.replace(position
, wcslen(win_folder_mapping
[i
].name
), path_string
);
89 // Next translate other windows specific variables.
90 size_t position
= result
.find(kUserNamePolicyVarName
);
91 if (position
!= std::wstring::npos
) {
92 DWORD return_length
= 0;
93 ::GetUserName(NULL
, &return_length
);
94 if (return_length
!= 0) {
95 scoped_ptr
<WCHAR
[]> username(new WCHAR
[return_length
]);
96 ::GetUserName(username
.get(), &return_length
);
97 std::wstring
username_string(username
.get());
98 result
.replace(position
, wcslen(kUserNamePolicyVarName
), username_string
);
101 position
= result
.find(kMachineNamePolicyVarName
);
102 if (position
!= std::wstring::npos
) {
103 DWORD return_length
= 0;
104 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname
, NULL
, &return_length
);
105 if (return_length
!= 0) {
106 scoped_ptr
<WCHAR
[]> machinename(new WCHAR
[return_length
]);
107 ::GetComputerNameEx(ComputerNamePhysicalDnsHostname
,
108 machinename
.get(), &return_length
);
109 std::wstring
machinename_string(machinename
.get());
111 position
, wcslen(kMachineNamePolicyVarName
), machinename_string
);
114 position
= result
.find(kWinClientName
);
115 if (position
!= std::wstring::npos
) {
116 LPWSTR buffer
= NULL
;
117 DWORD buffer_length
= 0;
118 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER
, WTS_CURRENT_SESSION
,
120 &buffer
, &buffer_length
)) {
121 std::wstring
clientname_string(buffer
);
122 result
.replace(position
, wcslen(kWinClientName
), clientname_string
);
123 ::WTSFreeMemory(buffer
);
126 position
= result
.find(kWinSessionName
);
127 if (position
!= std::wstring::npos
) {
128 LPWSTR buffer
= NULL
;
129 DWORD buffer_length
= 0;
130 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER
, WTS_CURRENT_SESSION
,
132 &buffer
, &buffer_length
)) {
133 std::wstring
sessionname_string(buffer
);
134 result
.replace(position
, wcslen(kWinSessionName
), sessionname_string
);
135 ::WTSFreeMemory(buffer
);
138 // TODO(pastarmovj): Consider reorganizing this code once there are even more
139 // variables to be supported. The search for the var and its replacement can
140 // be extracted as common functionality.
145 void CheckUserDataDirPolicy(base::FilePath
* user_data_dir
) {
146 DCHECK(user_data_dir
);
147 // Policy from the HKLM hive has precedence over HKCU.
148 if (!LoadUserDataDirPolicyFromRegistry(HKEY_LOCAL_MACHINE
, user_data_dir
))
149 LoadUserDataDirPolicyFromRegistry(HKEY_CURRENT_USER
, user_data_dir
);
152 } // namespace path_parser
154 } // namespace policy