OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/setup/daemon_controller_delegate_linux.h" | 5 #include "remoting/host/setup/daemon_controller_delegate_linux.h" |
6 | 6 |
7 #include <unistd.h> | 7 #include <unistd.h> |
8 | 8 |
9 #include "base/base_paths.h" | 9 #include "base/base_paths.h" |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "remoting/host/host_config.h" | 30 #include "remoting/host/host_config.h" |
31 #include "remoting/host/usage_stats_consent.h" | 31 #include "remoting/host/usage_stats_consent.h" |
32 | 32 |
33 namespace remoting { | 33 namespace remoting { |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 const char kDaemonScript[] = | 37 const char kDaemonScript[] = |
38 "/opt/google/chrome-remote-desktop/chrome-remote-desktop"; | 38 "/opt/google/chrome-remote-desktop/chrome-remote-desktop"; |
39 | 39 |
40 // Timeout for running daemon script. The script itself sets a timeout when | |
41 // waiting for the host to come online, so the setting here should be at least | |
42 // as long. | |
43 const int64 kDaemonTimeoutMs = 60000; | |
44 | |
45 // Timeout for commands that require password prompt - 5 minutes. | |
46 const int64 kSudoTimeoutSeconds = 5 * 60; | |
47 | |
48 base::FilePath GetConfigPath() { | 40 base::FilePath GetConfigPath() { |
49 std::string filename = | 41 std::string filename = |
50 "host#" + base::MD5String(net::GetHostName()) + ".json"; | 42 "host#" + base::MD5String(net::GetHostName()) + ".json"; |
51 base::FilePath homedir; | 43 base::FilePath homedir; |
52 PathService::Get(base::DIR_HOME, &homedir); | 44 PathService::Get(base::DIR_HOME, &homedir); |
53 return homedir.Append(".config/chrome-remote-desktop").Append(filename); | 45 return homedir.Append(".config/chrome-remote-desktop").Append(filename); |
54 } | 46 } |
55 | 47 |
56 bool GetScriptPath(base::FilePath* result) { | 48 bool GetScriptPath(base::FilePath* result) { |
57 base::FilePath candidate_exe(kDaemonScript); | 49 base::FilePath candidate_exe(kDaemonScript); |
58 if (access(candidate_exe.value().c_str(), X_OK) == 0) { | 50 if (access(candidate_exe.value().c_str(), X_OK) == 0) { |
59 *result = candidate_exe; | 51 *result = candidate_exe; |
60 return true; | 52 return true; |
61 } | 53 } |
62 return false; | 54 return false; |
63 } | 55 } |
64 | 56 |
65 bool RunHostScriptWithTimeout( | 57 bool RunHostScript(const std::vector<std::string>& args) { |
66 const std::vector<std::string>& args, | |
67 base::TimeDelta timeout, | |
68 int* exit_code) { | |
69 DCHECK(exit_code); | |
70 | |
71 // As long as we're relying on running an external binary from the | 58 // As long as we're relying on running an external binary from the |
72 // PATH, don't do it as root. | 59 // PATH, don't do it as root. |
73 if (getuid() == 0) { | 60 if (getuid() == 0) { |
74 LOG(ERROR) << "Refusing to run script as root."; | 61 LOG(ERROR) << "Refusing to run script as root."; |
75 return false; | 62 return false; |
76 } | 63 } |
77 base::FilePath script_path; | 64 base::FilePath script_path; |
78 if (!GetScriptPath(&script_path)) { | 65 if (!GetScriptPath(&script_path)) { |
79 LOG(ERROR) << "GetScriptPath() failed."; | 66 LOG(ERROR) << "GetScriptPath() failed."; |
80 return false; | 67 return false; |
81 } | 68 } |
82 base::CommandLine command_line(script_path); | 69 base::CommandLine command_line(script_path); |
83 for (unsigned int i = 0; i < args.size(); ++i) { | 70 for (unsigned int i = 0; i < args.size(); ++i) { |
84 command_line.AppendArg(args[i]); | 71 command_line.AppendArg(args[i]); |
85 } | 72 } |
86 | 73 |
87 // Redirect the child's stdout to the parent's stderr. In the case where this | 74 std::string output; |
88 // parent process is a Native Messaging host, its stdout is used to send | 75 bool result = base::GetAppOutputAndError(command_line, &output); |
89 // messages to the web-app. | 76 if (result) { |
90 base::FileHandleMappingVector fds_to_remap; | 77 LOG(INFO) << output; |
91 fds_to_remap.push_back(std::pair<int, int>(STDERR_FILENO, STDOUT_FILENO)); | 78 } else { |
92 base::LaunchOptions options; | 79 LOG(ERROR) << output; |
93 options.fds_to_remap = &fds_to_remap; | |
94 | |
95 #if !defined(OS_CHROMEOS) | |
96 options.allow_new_privs = true; | |
97 #endif | |
98 | |
99 base::Process process = base::LaunchProcess(command_line, options); | |
100 if (!process.IsValid()) { | |
101 LOG(ERROR) << "Failed to run command: " | |
102 << command_line.GetCommandLineString(); | |
103 return false; | |
104 } | 80 } |
105 | 81 |
106 if (!process.WaitForExitWithTimeout(timeout, exit_code)) { | 82 return result; |
107 process.Terminate(0, false); | |
108 LOG(ERROR) << "Timeout exceeded for command: " | |
109 << command_line.GetCommandLineString(); | |
110 return false; | |
111 } | |
112 | |
113 return true; | |
114 } | |
115 | |
116 bool RunHostScript(const std::vector<std::string>& args, int* exit_code) { | |
117 return RunHostScriptWithTimeout( | |
118 args, base::TimeDelta::FromMilliseconds(kDaemonTimeoutMs), exit_code); | |
119 } | 83 } |
120 | 84 |
121 } // namespace | 85 } // namespace |
122 | 86 |
123 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { | 87 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { |
124 } | 88 } |
125 | 89 |
126 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { | 90 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { |
127 } | 91 } |
128 | 92 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 return result.Pass(); | 143 return result.Pass(); |
180 } | 144 } |
181 | 145 |
182 void DaemonControllerDelegateLinux::SetConfigAndStart( | 146 void DaemonControllerDelegateLinux::SetConfigAndStart( |
183 scoped_ptr<base::DictionaryValue> config, | 147 scoped_ptr<base::DictionaryValue> config, |
184 bool consent, | 148 bool consent, |
185 const DaemonController::CompletionCallback& done) { | 149 const DaemonController::CompletionCallback& done) { |
186 // Add the user to chrome-remote-desktop group first. | 150 // Add the user to chrome-remote-desktop group first. |
187 std::vector<std::string> args; | 151 std::vector<std::string> args; |
188 args.push_back("--add-user"); | 152 args.push_back("--add-user"); |
189 int exit_code; | 153 if (!RunHostScript(args)) { |
190 if (!RunHostScriptWithTimeout( | |
191 args, base::TimeDelta::FromSeconds(kSudoTimeoutSeconds), | |
192 &exit_code) || | |
193 exit_code != 0) { | |
194 LOG(ERROR) << "Failed to add user to chrome-remote-desktop group."; | 154 LOG(ERROR) << "Failed to add user to chrome-remote-desktop group."; |
195 done.Run(DaemonController::RESULT_FAILED); | 155 done.Run(DaemonController::RESULT_FAILED); |
196 return; | 156 return; |
197 } | 157 } |
198 | 158 |
199 // Ensure the configuration directory exists. | 159 // Ensure the configuration directory exists. |
200 base::FilePath config_dir = GetConfigPath().DirName(); | 160 base::FilePath config_dir = GetConfigPath().DirName(); |
201 if (!base::DirectoryExists(config_dir) && | 161 if (!base::DirectoryExists(config_dir) && |
202 !base::CreateDirectory(config_dir)) { | 162 !base::CreateDirectory(config_dir)) { |
203 LOG(ERROR) << "Failed to create config directory " << config_dir.value(); | 163 LOG(ERROR) << "Failed to create config directory " << config_dir.value(); |
204 done.Run(DaemonController::RESULT_FAILED); | 164 done.Run(DaemonController::RESULT_FAILED); |
205 return; | 165 return; |
206 } | 166 } |
207 | 167 |
208 // Write config. | 168 // Write config. |
209 if (!HostConfigToJsonFile(*config, GetConfigPath())) { | 169 if (!HostConfigToJsonFile(*config, GetConfigPath())) { |
210 LOG(ERROR) << "Failed to update config file."; | 170 LOG(ERROR) << "Failed to update config file."; |
211 done.Run(DaemonController::RESULT_FAILED); | 171 done.Run(DaemonController::RESULT_FAILED); |
212 return; | 172 return; |
213 } | 173 } |
214 | 174 |
215 // Finally start the host. | 175 // Finally start the host. |
216 args.clear(); | 176 args.clear(); |
217 args.push_back("--start"); | 177 args.push_back("--start"); |
218 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 178 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; |
219 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 179 if (RunHostScript(args)) |
220 result = DaemonController::RESULT_OK; | 180 result = DaemonController::RESULT_OK; |
221 | 181 |
222 done.Run(result); | 182 done.Run(result); |
223 } | 183 } |
224 | 184 |
225 void DaemonControllerDelegateLinux::UpdateConfig( | 185 void DaemonControllerDelegateLinux::UpdateConfig( |
226 scoped_ptr<base::DictionaryValue> config, | 186 scoped_ptr<base::DictionaryValue> config, |
227 const DaemonController::CompletionCallback& done) { | 187 const DaemonController::CompletionCallback& done) { |
228 scoped_ptr<base::DictionaryValue> new_config( | 188 scoped_ptr<base::DictionaryValue> new_config( |
229 HostConfigFromJsonFile(GetConfigPath())); | 189 HostConfigFromJsonFile(GetConfigPath())); |
230 if (new_config) | 190 if (new_config) |
231 new_config->MergeDictionary(config.get()); | 191 new_config->MergeDictionary(config.get()); |
232 if (!new_config || !HostConfigToJsonFile(*new_config, GetConfigPath())) { | 192 if (!new_config || !HostConfigToJsonFile(*new_config, GetConfigPath())) { |
233 LOG(ERROR) << "Failed to update config file."; | 193 LOG(ERROR) << "Failed to update config file."; |
234 done.Run(DaemonController::RESULT_FAILED); | 194 done.Run(DaemonController::RESULT_FAILED); |
235 return; | 195 return; |
236 } | 196 } |
237 | 197 |
238 std::vector<std::string> args; | 198 std::vector<std::string> args; |
239 args.push_back("--reload"); | 199 args.push_back("--reload"); |
240 int exit_code = 0; | |
241 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 200 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; |
242 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 201 if (RunHostScript(args)) |
243 result = DaemonController::RESULT_OK; | 202 result = DaemonController::RESULT_OK; |
244 | 203 |
245 done.Run(result); | 204 done.Run(result); |
246 } | 205 } |
247 | 206 |
248 void DaemonControllerDelegateLinux::Stop( | 207 void DaemonControllerDelegateLinux::Stop( |
249 const DaemonController::CompletionCallback& done) { | 208 const DaemonController::CompletionCallback& done) { |
250 std::vector<std::string> args; | 209 std::vector<std::string> args; |
251 args.push_back("--stop"); | 210 args.push_back("--stop"); |
252 int exit_code = 0; | |
253 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 211 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; |
254 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 212 if (RunHostScript(args)) |
255 result = DaemonController::RESULT_OK; | 213 result = DaemonController::RESULT_OK; |
256 | 214 |
257 done.Run(result); | 215 done.Run(result); |
258 } | 216 } |
259 | 217 |
260 DaemonController::UsageStatsConsent | 218 DaemonController::UsageStatsConsent |
261 DaemonControllerDelegateLinux::GetUsageStatsConsent() { | 219 DaemonControllerDelegateLinux::GetUsageStatsConsent() { |
262 // Crash dump collection is not implemented on Linux yet. | 220 // Crash dump collection is not implemented on Linux yet. |
263 // http://crbug.com/130678. | 221 // http://crbug.com/130678. |
264 DaemonController::UsageStatsConsent consent; | 222 DaemonController::UsageStatsConsent consent; |
265 consent.supported = false; | 223 consent.supported = false; |
266 consent.allowed = false; | 224 consent.allowed = false; |
267 consent.set_by_policy = false; | 225 consent.set_by_policy = false; |
268 return consent; | 226 return consent; |
269 } | 227 } |
270 | 228 |
271 scoped_refptr<DaemonController> DaemonController::Create() { | 229 scoped_refptr<DaemonController> DaemonController::Create() { |
272 scoped_ptr<DaemonController::Delegate> delegate( | 230 scoped_ptr<DaemonController::Delegate> delegate( |
273 new DaemonControllerDelegateLinux()); | 231 new DaemonControllerDelegateLinux()); |
274 return new DaemonController(delegate.Pass()); | 232 return new DaemonController(delegate.Pass()); |
275 } | 233 } |
276 | 234 |
277 } // namespace remoting | 235 } // namespace remoting |
OLD | NEW |