| 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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 if (access(candidate_exe.value().c_str(), X_OK) == 0) { | 58 if (access(candidate_exe.value().c_str(), X_OK) == 0) { |
| 59 *result = candidate_exe; | 59 *result = candidate_exe; |
| 60 return true; | 60 return true; |
| 61 } | 61 } |
| 62 return false; | 62 return false; |
| 63 } | 63 } |
| 64 | 64 |
| 65 bool RunHostScriptWithTimeout( | 65 bool RunHostScriptWithTimeout( |
| 66 const std::vector<std::string>& args, | 66 const std::vector<std::string>& args, |
| 67 base::TimeDelta timeout, | 67 base::TimeDelta timeout, |
| 68 int* exit_code) { | 68 const DaemonController::ErrorCallback& on_error) { |
| 69 DCHECK(exit_code); | |
| 70 | 69 |
| 71 // As long as we're relying on running an external binary from the | 70 // As long as we're relying on running an external binary from the |
| 72 // PATH, don't do it as root. | 71 // PATH, don't do it as root. |
| 73 if (getuid() == 0) { | 72 if (getuid() == 0) { |
| 74 LOG(ERROR) << "Refusing to run script as root."; | 73 std::string error_message = "Refusing to run script as root"; |
| 74 LOG(ERROR) << error_message; |
| 75 on_error.Run(error_message, FROM_HERE); |
| 75 return false; | 76 return false; |
| 76 } | 77 } |
| 78 |
| 77 base::FilePath script_path; | 79 base::FilePath script_path; |
| 78 if (!GetScriptPath(&script_path)) { | 80 if (!GetScriptPath(&script_path)) { |
| 79 LOG(ERROR) << "GetScriptPath() failed."; | 81 std::string error_message = "GetScriptPath() failed"; |
| 82 LOG(ERROR) << error_message; |
| 83 on_error.Run(error_message, FROM_HERE); |
| 80 return false; | 84 return false; |
| 81 } | 85 } |
| 86 |
| 82 base::CommandLine command_line(script_path); | 87 base::CommandLine command_line(script_path); |
| 83 for (unsigned int i = 0; i < args.size(); ++i) { | 88 for (unsigned int i = 0; i < args.size(); ++i) { |
| 84 command_line.AppendArg(args[i]); | 89 command_line.AppendArg(args[i]); |
| 85 } | 90 } |
| 86 | 91 |
| 87 // Redirect the child's stdout to the parent's stderr. In the case where this | 92 // Redirect the child's stdout to the parent's stderr. In the case where this |
| 88 // parent process is a Native Messaging host, its stdout is used to send | 93 // parent process is a Native Messaging host, its stdout is used to send |
| 89 // messages to the web-app. | 94 // messages to the web-app. |
| 90 base::FileHandleMappingVector fds_to_remap; | 95 base::FileHandleMappingVector fds_to_remap; |
| 91 fds_to_remap.push_back(std::pair<int, int>(STDERR_FILENO, STDOUT_FILENO)); | 96 fds_to_remap.push_back(std::pair<int, int>(STDERR_FILENO, STDOUT_FILENO)); |
| 92 base::LaunchOptions options; | 97 base::LaunchOptions options; |
| 93 options.fds_to_remap = &fds_to_remap; | 98 options.fds_to_remap = &fds_to_remap; |
| 94 | 99 |
| 95 #if !defined(OS_CHROMEOS) | 100 #if !defined(OS_CHROMEOS) |
| 96 options.allow_new_privs = true; | 101 options.allow_new_privs = true; |
| 97 #endif | 102 #endif |
| 98 | 103 |
| 99 base::Process process = base::LaunchProcess(command_line, options); | 104 base::Process process = base::LaunchProcess(command_line, options); |
| 100 if (!process.IsValid()) { | 105 if (!process.IsValid()) { |
| 101 LOG(ERROR) << "Failed to run command: " | 106 std::string error_message = |
| 102 << command_line.GetCommandLineString(); | 107 "Failed to run command: " + command_line.GetCommandLineString(); |
| 108 LOG(ERROR) << error_message; |
| 109 on_error.Run(error_message, FROM_HERE); |
| 103 return false; | 110 return false; |
| 104 } | 111 } |
| 105 | 112 |
| 106 if (!process.WaitForExitWithTimeout(timeout, exit_code)) { | 113 int exit_code; |
| 114 if (!process.WaitForExitWithTimeout(timeout, &exit_code)) { |
| 107 process.Terminate(0, false); | 115 process.Terminate(0, false); |
| 108 LOG(ERROR) << "Timeout exceeded for command: " | 116 std::string error_message = |
| 109 << command_line.GetCommandLineString(); | 117 "Timeout exceeded for command: " + command_line.GetCommandLineString(); |
| 118 LOG(ERROR) << error_message; |
| 119 on_error.Run(error_message, FROM_HERE); |
| 110 return false; | 120 return false; |
| 111 } | 121 } |
| 112 | 122 |
| 123 if (exit_code != 0) { |
| 124 std::ostringstream error_message; |
| 125 error_message << "Non-zero exit code " << exit_code << " from command: " |
| 126 << command_line.GetCommandLineString(); |
| 127 LOG(ERROR) << error_message; |
| 128 on_error.Run(error_message.str(), FROM_HERE); |
| 129 } |
| 130 |
| 113 return true; | 131 return true; |
| 114 } | 132 } |
| 115 | 133 |
| 116 bool RunHostScript(const std::vector<std::string>& args, int* exit_code) { | 134 bool RunHostScript(const std::vector<std::string>& args, |
| 135 const DaemonController::ErrorCallback& on_error) { |
| 117 return RunHostScriptWithTimeout( | 136 return RunHostScriptWithTimeout( |
| 118 args, base::TimeDelta::FromMilliseconds(kDaemonTimeoutMs), exit_code); | 137 args, |
| 138 base::TimeDelta::FromMilliseconds(kDaemonTimeoutMs), |
| 139 on_error); |
| 119 } | 140 } |
| 120 | 141 |
| 121 } // namespace | 142 } // namespace |
| 122 | 143 |
| 123 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { | 144 DaemonControllerDelegateLinux::DaemonControllerDelegateLinux() { |
| 124 } | 145 } |
| 125 | 146 |
| 126 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { | 147 DaemonControllerDelegateLinux::~DaemonControllerDelegateLinux() { |
| 127 } | 148 } |
| 128 | 149 |
| 129 DaemonController::State DaemonControllerDelegateLinux::GetState() { | 150 DaemonController::State DaemonControllerDelegateLinux::GetState() { |
| 130 base::FilePath script_path; | 151 base::FilePath script_path; |
| 131 if (!GetScriptPath(&script_path)) { | 152 if (!GetScriptPath(&script_path)) { |
| 132 LOG(ERROR) << "GetScriptPath() failed."; | 153 LOG(ERROR) << "GetScriptPath() failed"; |
| 133 return DaemonController::STATE_UNKNOWN; | 154 return DaemonController::STATE_UNKNOWN; |
| 134 } | 155 } |
| 135 base::CommandLine command_line(script_path); | 156 base::CommandLine command_line(script_path); |
| 136 command_line.AppendArg("--get-status"); | 157 command_line.AppendArg("--get-status"); |
| 137 | 158 |
| 138 std::string status; | 159 std::string status; |
| 139 int exit_code = 0; | 160 int exit_code = 0; |
| 140 if (!base::GetAppOutputWithExitCode(command_line, &status, &exit_code) || | 161 if (!base::GetAppOutputWithExitCode(command_line, &status, &exit_code) || |
| 141 exit_code != 0) { | 162 exit_code != 0) { |
| 142 LOG(ERROR) << "Failed to run \"" << command_line.GetCommandLineString() | 163 LOG(ERROR) << "Failed to run \"" << command_line.GetCommandLineString() |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 } | 196 } |
| 176 if (config->GetString(kXmppLoginConfigPath, &value)) { | 197 if (config->GetString(kXmppLoginConfigPath, &value)) { |
| 177 result->SetString(kXmppLoginConfigPath, value); | 198 result->SetString(kXmppLoginConfigPath, value); |
| 178 } | 199 } |
| 179 return result.Pass(); | 200 return result.Pass(); |
| 180 } | 201 } |
| 181 | 202 |
| 182 void DaemonControllerDelegateLinux::SetConfigAndStart( | 203 void DaemonControllerDelegateLinux::SetConfigAndStart( |
| 183 scoped_ptr<base::DictionaryValue> config, | 204 scoped_ptr<base::DictionaryValue> config, |
| 184 bool consent, | 205 bool consent, |
| 185 const DaemonController::CompletionCallback& done) { | 206 const base::Closure& on_done, |
| 207 const DaemonController::ErrorCallback& on_error) { |
| 186 // Add the user to chrome-remote-desktop group first. | 208 // Add the user to chrome-remote-desktop group first. |
| 187 std::vector<std::string> args; | 209 std::vector<std::string> args; |
| 188 args.push_back("--add-user"); | 210 args.push_back("--add-user"); |
| 189 int exit_code; | |
| 190 if (!RunHostScriptWithTimeout( | 211 if (!RunHostScriptWithTimeout( |
| 191 args, base::TimeDelta::FromSeconds(kSudoTimeoutSeconds), | 212 args, base::TimeDelta::FromSeconds(kSudoTimeoutSeconds), |
| 192 &exit_code) || | 213 on_error)) { |
| 193 exit_code != 0) { | |
| 194 LOG(ERROR) << "Failed to add user to chrome-remote-desktop group."; | |
| 195 done.Run(DaemonController::RESULT_FAILED); | |
| 196 return; | 214 return; |
| 197 } | 215 } |
| 198 | 216 |
| 199 // Ensure the configuration directory exists. | 217 // Ensure the configuration directory exists. |
| 200 base::FilePath config_dir = GetConfigPath().DirName(); | 218 base::FilePath config_dir = GetConfigPath().DirName(); |
| 201 if (!base::DirectoryExists(config_dir) && | 219 if (!base::DirectoryExists(config_dir) && |
| 202 !base::CreateDirectory(config_dir)) { | 220 !base::CreateDirectory(config_dir)) { |
| 203 LOG(ERROR) << "Failed to create config directory " << config_dir.value(); | 221 std::string error_message = |
| 204 done.Run(DaemonController::RESULT_FAILED); | 222 "Failed to create config directory " + config_dir.value(); |
| 223 LOG(ERROR) << error_message; |
| 224 on_error.Run(error_message, FROM_HERE); |
| 205 return; | 225 return; |
| 206 } | 226 } |
| 207 | 227 |
| 208 // Write config. | 228 // Write config. |
| 209 if (!HostConfigToJsonFile(*config, GetConfigPath())) { | 229 if (!HostConfigToJsonFile(*config, GetConfigPath())) { |
| 210 LOG(ERROR) << "Failed to update config file."; | 230 std::string error_message = "Failed to update config file"; |
| 211 done.Run(DaemonController::RESULT_FAILED); | 231 LOG(ERROR) << error_message; |
| 232 on_error.Run(error_message, FROM_HERE); |
| 212 return; | 233 return; |
| 213 } | 234 } |
| 214 | 235 |
| 215 // Finally start the host. | 236 // Finally start the host. |
| 216 args.clear(); | 237 args.clear(); |
| 217 args.push_back("--start"); | 238 args.push_back("--start"); |
| 218 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 239 if (RunHostScript(args, on_error)) { |
| 219 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 240 on_done.Run(); |
| 220 result = DaemonController::RESULT_OK; | 241 } |
| 221 | |
| 222 done.Run(result); | |
| 223 } | 242 } |
| 224 | 243 |
| 225 void DaemonControllerDelegateLinux::UpdateConfig( | 244 void DaemonControllerDelegateLinux::UpdateConfig( |
| 226 scoped_ptr<base::DictionaryValue> config, | 245 scoped_ptr<base::DictionaryValue> config, |
| 227 const DaemonController::CompletionCallback& done) { | 246 const base::Closure& on_done, |
| 247 const DaemonController::ErrorCallback& on_error) { |
| 228 scoped_ptr<base::DictionaryValue> new_config( | 248 scoped_ptr<base::DictionaryValue> new_config( |
| 229 HostConfigFromJsonFile(GetConfigPath())); | 249 HostConfigFromJsonFile(GetConfigPath())); |
| 230 if (new_config) | 250 if (!new_config) { |
| 231 new_config->MergeDictionary(config.get()); | 251 std::string error_message = |
| 232 if (!new_config || !HostConfigToJsonFile(*new_config, GetConfigPath())) { | 252 "Reading config from " + GetConfigPath().value() + " failed"; |
| 233 LOG(ERROR) << "Failed to update config file."; | 253 LOG(ERROR) << error_message; |
| 234 done.Run(DaemonController::RESULT_FAILED); | 254 on_error.Run(error_message, FROM_HERE); |
| 255 return; |
| 256 } |
| 257 |
| 258 new_config->MergeDictionary(config.get()); |
| 259 if (!HostConfigToJsonFile(*new_config, GetConfigPath())) { |
| 260 std::string error_message = |
| 261 "Writing config to " + GetConfigPath().value() + " failed"; |
| 262 LOG(ERROR) << error_message; |
| 263 on_error.Run(error_message, FROM_HERE); |
| 235 return; | 264 return; |
| 236 } | 265 } |
| 237 | 266 |
| 238 std::vector<std::string> args; | 267 std::vector<std::string> args; |
| 239 args.push_back("--reload"); | 268 args.push_back("--reload"); |
| 240 int exit_code = 0; | 269 if (RunHostScript(args, on_error)) { |
| 241 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 270 on_done.Run(); |
| 242 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 271 } |
| 243 result = DaemonController::RESULT_OK; | |
| 244 | |
| 245 done.Run(result); | |
| 246 } | 272 } |
| 247 | 273 |
| 248 void DaemonControllerDelegateLinux::Stop( | 274 void DaemonControllerDelegateLinux::Stop( |
| 249 const DaemonController::CompletionCallback& done) { | 275 const base::Closure& on_done, |
| 276 const DaemonController::ErrorCallback& on_error) { |
| 250 std::vector<std::string> args; | 277 std::vector<std::string> args; |
| 251 args.push_back("--stop"); | 278 args.push_back("--stop"); |
| 252 int exit_code = 0; | 279 if (RunHostScript(args, on_error)) { |
| 253 DaemonController::AsyncResult result = DaemonController::RESULT_FAILED; | 280 on_done.Run(); |
| 254 if (RunHostScript(args, &exit_code) && (exit_code == 0)) | 281 } |
| 255 result = DaemonController::RESULT_OK; | |
| 256 | |
| 257 done.Run(result); | |
| 258 } | 282 } |
| 259 | 283 |
| 260 DaemonController::UsageStatsConsent | 284 DaemonController::UsageStatsConsent |
| 261 DaemonControllerDelegateLinux::GetUsageStatsConsent() { | 285 DaemonControllerDelegateLinux::GetUsageStatsConsent() { |
| 262 // Crash dump collection is not implemented on Linux yet. | 286 // Crash dump collection is not implemented on Linux yet. |
| 263 // http://crbug.com/130678. | 287 // http://crbug.com/130678. |
| 264 DaemonController::UsageStatsConsent consent; | 288 DaemonController::UsageStatsConsent consent; |
| 265 consent.supported = false; | 289 consent.supported = false; |
| 266 consent.allowed = false; | 290 consent.allowed = false; |
| 267 consent.set_by_policy = false; | 291 consent.set_by_policy = false; |
| 268 return consent; | 292 return consent; |
| 269 } | 293 } |
| 270 | 294 |
| 271 scoped_refptr<DaemonController> DaemonController::Create() { | 295 scoped_refptr<DaemonController> DaemonController::Create() { |
| 272 scoped_ptr<DaemonController::Delegate> delegate( | 296 scoped_ptr<DaemonController::Delegate> delegate( |
| 273 new DaemonControllerDelegateLinux()); | 297 new DaemonControllerDelegateLinux()); |
| 274 return new DaemonController(delegate.Pass()); | 298 return new DaemonController(delegate.Pass()); |
| 275 } | 299 } |
| 276 | 300 |
| 277 } // namespace remoting | 301 } // namespace remoting |
| OLD | NEW |