1 // Copyright (c) 2012 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.
5 #include "chrome_frame/chrome_launcher.h"
11 #include "policy/policy_constants.h"
13 // Herein lies stuff selectively stolen from Chrome. We don't pull it in
14 // directly because all of it results in many things we don't want being
18 // These are the switches we will allow (along with their values) in the
19 // safe-for-Low-Integrity version of the Chrome command line.
20 // Including the chrome switch files pulls in a bunch of dependencies sadly, so
21 // we redefine things here:
22 const wchar_t* kAllowedSwitches
[] = {
23 L
"automation-channel",
25 L
"chrome-frame-shutdown-delay",
27 L
"disable-background-mode",
28 L
"disable-popup-blocking",
29 L
"disable-print-preview",
30 L
"disable-renderer-accessibility",
31 L
"enable-experimental-extension-apis",
32 L
"force-renderer-accessibility",
33 L
"full-memory-crash-report",
35 L
"no-default-browser-check",
41 const wchar_t kWhitespaceChars
[] = {
42 0x0009, /* <control-0009> to <control-000D> */
48 0x0085, /* <control-0085> */
49 0x00A0, /* No-Break Space */
50 0x1680, /* Ogham Space Mark */
51 0x180E, /* Mongolian Vowel Separator */
52 0x2000, /* En Quad to Hair Space */
63 0x200C, /* Zero Width Non-Joiner */
64 0x2028, /* Line Separator */
65 0x2029, /* Paragraph Separator */
66 0x202F, /* Narrow No-Break Space */
67 0x205F, /* Medium Mathematical Space */
68 0x3000, /* Ideographic Space */
72 const wchar_t kLauncherExeBaseName
[] = L
"chrome_launcher.exe";
73 const wchar_t kBrowserProcessExecutableName
[] = L
"chrome.exe";
78 namespace chrome_launcher
{
80 std::wstring
TrimWhiteSpace(const wchar_t* input_str
) {
82 if (input_str
!= NULL
) {
83 std::wstring
str(input_str
);
85 const std::wstring::size_type first_good_char
=
86 str
.find_first_not_of(kWhitespaceChars
);
87 const std::wstring::size_type last_good_char
=
88 str
.find_last_not_of(kWhitespaceChars
);
90 if (first_good_char
!= std::wstring::npos
&&
91 last_good_char
!= std::wstring::npos
&&
92 last_good_char
>= first_good_char
) {
93 // + 1 because find_last_not_of returns the index, and we want the count
94 output
= str
.substr(first_good_char
,
95 last_good_char
- first_good_char
+ 1);
102 bool IsValidArgument(const std::wstring
& arg
) {
103 if (arg
.length() < 2) {
107 for (int i
= 0; i
< arraysize(kAllowedSwitches
); ++i
) {
108 size_t arg_length
= lstrlenW(kAllowedSwitches
[i
]);
109 if (arg
.find(kAllowedSwitches
[i
], 2) == 2) {
110 // The argument starts off right, now it must either end here, or be
111 // followed by an equals sign.
112 if (arg
.length() == (arg_length
+ 2) ||
113 (arg
.length() > (arg_length
+ 2) && arg
[arg_length
+2] == L
'=')) {
122 bool IsValidCommandLine(const wchar_t* command_line
) {
123 if (command_line
== NULL
) {
128 wchar_t** args
= NULL
;
129 args
= CommandLineToArgvW(command_line
, &num_args
);
132 // Note that we skip args[0] since that is just our executable name and
133 // doesn't get passed through to Chrome.
134 for (int i
= 1; i
< num_args
; ++i
) {
135 std::wstring trimmed_arg
= TrimWhiteSpace(args
[i
]);
136 if (!IsValidArgument(trimmed_arg
.c_str())) {
145 // Looks up optionally configured launch parameters for Chrome that may have
146 // been set via group policy.
147 void AppendAdditionalLaunchParameters(std::wstring
* command_line
) {
148 static const HKEY kRootKeys
[] = {
153 std::wstring
launch_params_value_name(
154 &policy::key::kAdditionalLaunchParameters
[0],
155 &policy::key::kAdditionalLaunchParameters
[
156 lstrlenA(policy::key::kAdditionalLaunchParameters
)]);
158 // Used for basic checks since CreateProcess doesn't support command lines
159 // longer than 0x8000 characters. If we surpass that length, we do not add the
160 // additional parameters. Because we need to add a space before the
161 // extra parameters, we use 0x7fff and not 0x8000.
162 const size_t kMaxChars
= 0x7FFF - command_line
->size();
166 for (int i
= 0; !found
&& i
< arraysize(kRootKeys
); ++i
) {
167 result
= ::RegOpenKeyExW(kRootKeys
[i
], policy::kRegistryMandatorySubKey
, 0,
168 KEY_QUERY_VALUE
, &key
);
169 if (result
== ERROR_SUCCESS
) {
172 result
= RegQueryValueExW(key
, launch_params_value_name
.c_str(),
173 0, &type
, NULL
, &size
);
174 if (result
== ERROR_SUCCESS
&& type
== REG_SZ
&& size
> 0 &&
175 (size
/ sizeof(wchar_t)) < kMaxChars
) {
176 // This size includes any terminating null character or characters
177 // unless the data was stored without them, so for safety we allocate
178 // one extra char and zero out the buffer.
179 wchar_t* value
= new wchar_t[(size
/ sizeof(wchar_t)) + 1];
180 memset(value
, 0, size
+ sizeof(wchar_t));
181 result
= RegQueryValueExW(key
, launch_params_value_name
.c_str(), 0,
182 &type
, reinterpret_cast<BYTE
*>(&value
[0]),
184 if (result
== ERROR_SUCCESS
) {
185 *command_line
+= L
' ';
186 *command_line
+= value
;
196 bool SanitizeAndLaunchChrome(const wchar_t* command_line
) {
197 bool success
= false;
198 if (IsValidCommandLine(command_line
)) {
199 std::wstring chrome_path
;
200 if (GetChromeExecutablePath(&chrome_path
)) {
201 const wchar_t* args
= PathGetArgs(command_line
);
203 // Build the command line string with the quoted path to chrome.exe.
204 std::wstring command_line
;
205 command_line
.reserve(chrome_path
.size() + 2);
206 command_line
.append(1, L
'\"').append(chrome_path
).append(1, L
'\"');
209 command_line
+= L
' ';
210 command_line
+= args
;
213 // Append parameters that might be set by group policy.
214 AppendAdditionalLaunchParameters(&command_line
);
216 STARTUPINFO startup_info
= {0};
217 startup_info
.cb
= sizeof(startup_info
);
218 startup_info
.dwFlags
= STARTF_USESHOWWINDOW
;
219 startup_info
.wShowWindow
= SW_SHOW
;
220 PROCESS_INFORMATION process_info
= {0};
221 if (CreateProcess(&chrome_path
[0], &command_line
[0],
222 NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
223 &startup_info
, &process_info
)) {
225 CloseHandle(process_info
.hThread
);
226 CloseHandle(process_info
.hProcess
);
237 bool GetChromeExecutablePath(std::wstring
* chrome_path
) {
238 _ASSERT(chrome_path
);
240 wchar_t cur_path
[MAX_PATH
* 4] = {0};
241 // Assume that we are always built into an exe.
242 GetModuleFileName(NULL
, cur_path
, arraysize(cur_path
) / 2);
244 PathRemoveFileSpec(cur_path
);
246 bool success
= false;
247 if (PathAppend(cur_path
, kBrowserProcessExecutableName
)) {
248 if (!PathFileExists(cur_path
)) {
249 // The installation model for Chrome places the DLLs in a versioned
250 // sub-folder one down from the Chrome executable. If we fail to find
251 // chrome.exe in the current path, try looking one up and launching that
252 // instead. In practice, that means we back up two and append the
253 // executable name again.
254 PathRemoveFileSpec(cur_path
);
255 PathRemoveFileSpec(cur_path
);
256 PathAppend(cur_path
, kBrowserProcessExecutableName
);
259 if (PathFileExists(cur_path
)) {
260 *chrome_path
= cur_path
;
268 } // namespace chrome_launcher