Copy default apps for managed users into artifacts directory (part 2)
[chromium-blink-merge.git] / chrome_frame / chrome_launcher.cc
blob88fc0dab7dce78d7f3add8ac846359d9df7d7073
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"
7 #include <windows.h>
8 #include <shellapi.h>
9 #include <shlwapi.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
15 // included as well.
16 namespace {
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",
24 L"chrome-frame",
25 L"chrome-frame-shutdown-delay",
26 L"chrome-version",
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",
34 L"lang",
35 L"no-default-browser-check",
36 L"no-first-run",
37 L"noerrdialogs",
38 L"user-data-dir",
41 const wchar_t kWhitespaceChars[] = {
42 0x0009, /* <control-0009> to <control-000D> */
43 0x000A,
44 0x000B,
45 0x000C,
46 0x000D,
47 0x0020, /* Space */
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 */
53 0x2001,
54 0x2002,
55 0x2003,
56 0x2004,
57 0x2005,
58 0x2006,
59 0x2007,
60 0x2008,
61 0x2009,
62 0x200A,
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";
75 } // end namespace
78 namespace chrome_launcher {
80 std::wstring TrimWhiteSpace(const wchar_t* input_str) {
81 std::wstring output;
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);
99 return output;
102 bool IsValidArgument(const std::wstring& arg) {
103 if (arg.length() < 2) {
104 return false;
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'=')) {
114 return true;
119 return false;
122 bool IsValidCommandLine(const wchar_t* command_line) {
123 if (command_line == NULL) {
124 return false;
127 int num_args = 0;
128 wchar_t** args = NULL;
129 args = CommandLineToArgvW(command_line, &num_args);
131 bool success = true;
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())) {
137 success = false;
138 break;
142 return success;
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[] = {
149 HKEY_LOCAL_MACHINE,
150 HKEY_CURRENT_USER
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();
163 HKEY key;
164 LONG result;
165 bool found = false;
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) {
170 DWORD size = 0;
171 DWORD type = 0;
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]),
183 &size);
184 if (result == ERROR_SUCCESS) {
185 *command_line += L' ';
186 *command_line += value;
187 found = true;
189 delete [] value;
191 ::RegCloseKey(key);
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'\"');
208 if (args != NULL) {
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)) {
224 // Close handles.
225 CloseHandle(process_info.hThread);
226 CloseHandle(process_info.hProcess);
227 success = true;
228 } else {
229 _ASSERT(FALSE);
234 return success;
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;
261 success = true;
265 return success;
268 } // namespace chrome_launcher