OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
6 // running within user sessions. | 6 // running within user sessions. |
7 | 7 |
8 #include "remoting/host/win/host_service.h" | 8 #include "remoting/host/win/host_service.h" |
9 | 9 |
10 #include <windows.h> | 10 #include <windows.h> |
11 #include <shellapi.h> | |
11 #include <wtsapi32.h> | 12 #include <wtsapi32.h> |
12 #include <stdio.h> | |
13 | 13 |
14 #include "base/at_exit.h" | 14 #include "base/at_exit.h" |
15 #include "base/base_paths.h" | 15 #include "base/base_paths.h" |
16 #include "base/base_switches.h" | |
16 #include "base/bind.h" | 17 #include "base/bind.h" |
17 #include "base/command_line.h" | 18 #include "base/command_line.h" |
18 #include "base/file_path.h" | 19 #include "base/file_path.h" |
19 #include "base/logging.h" | 20 #include "base/logging.h" |
20 #include "base/message_loop.h" | 21 #include "base/message_loop.h" |
21 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
22 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
23 #include "base/threading/thread.h" | 24 #include "base/threading/thread.h" |
24 #include "base/utf_string_conversions.h" | 25 #include "base/utf_string_conversions.h" |
25 #include "base/win/wrapped_window_proc.h" | 26 #include "base/win/wrapped_window_proc.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
46 | 47 |
47 // Session id that does not represent any session. | 48 // Session id that does not represent any session. |
48 const uint32 kInvalidSessionId = 0xffffffffu; | 49 const uint32 kInvalidSessionId = 0xffffffffu; |
49 | 50 |
50 const char kIoThreadName[] = "I/O thread"; | 51 const char kIoThreadName[] = "I/O thread"; |
51 | 52 |
52 // A window class for the session change notifications window. | 53 // A window class for the session change notifications window. |
53 const wchar_t kSessionNotificationWindowClass[] = | 54 const wchar_t kSessionNotificationWindowClass[] = |
54 L"Chromoting_SessionNotificationWindow"; | 55 L"Chromoting_SessionNotificationWindow"; |
55 | 56 |
56 // Command line actions and switches: | 57 // Command line switches: |
57 // "run" sumply runs the service as usual. | |
58 const wchar_t kRunActionName[] = L"run"; | |
59 | 58 |
60 // "--console" runs the service interactively for debugging purposes. | 59 // "--console" runs the service interactively for debugging purposes. |
61 const char kConsoleSwitchName[] = "console"; | 60 const char kConsoleSwitchName[] = "console"; |
62 | 61 |
62 // "--elevate=<binary>" requests <binary> to be launched elevated, presenting | |
63 // a UAC promt if necessary. | |
Wez
2012/08/15 23:22:20
typo: prompt
alexeypa (please no reviews)
2012/08/15 23:55:50
Done.
| |
64 const char kElevateSwitchName[] = "elevate"; | |
65 | |
63 // "--help" or "--?" prints the usage message. | 66 // "--help" or "--?" prints the usage message. |
64 const char kHelpSwitchName[] = "help"; | 67 const char kHelpSwitchName[] = "help"; |
65 const char kQuestionSwitchName[] = "?"; | 68 const char kQuestionSwitchName[] = "?"; |
66 | 69 |
67 const char kUsageMessage[] = | 70 const wchar_t kUsageMessage[] = |
68 "\n" | 71 L"\n" |
69 "Usage: %s [action] [options]\n" | 72 L"Usage: %ls [options]\n" |
70 "\n" | 73 L"\n" |
71 "Actions:\n" | 74 L"Options:\n" |
72 " run - Run the service (default if no action was specified).\n" | 75 L" --console - Run the service interactively for debugging purposes.\n" |
73 "\n" | 76 L" --elevate=<...> - Run <...> elevated.\n" |
74 "Options:\n" | 77 L" --help, --? - Print this message.\n"; |
75 " --console - Run the service interactively for debugging purposes.\n" | 78 |
76 " --help, --? - Print this message.\n"; | 79 // The command line parameters that should be copied from the service's command |
80 // line when launching an elevated child. | |
81 const char* kCopiedSwitchNames[] = { | |
82 "auth-config", "host-config", switches::kV, switches::kVModule }; | |
77 | 83 |
78 // Exit codes: | 84 // Exit codes: |
79 const int kSuccessExitCode = 0; | 85 const int kSuccessExitCode = 0; |
80 const int kUsageExitCode = 1; | 86 const int kUsageExitCode = 1; |
81 const int kErrorExitCode = 2; | 87 const int kErrorExitCode = 2; |
82 | 88 |
83 void usage(const char* program_name) { | 89 void usage(const FilePath& program_name) { |
84 fprintf(stderr, kUsageMessage, program_name); | 90 LOG(INFO) << StringPrintf(kUsageMessage, |
91 UTF16ToWide(program_name.value()).c_str()); | |
85 } | 92 } |
86 | 93 |
87 } // namespace | 94 } // namespace |
88 | 95 |
89 namespace remoting { | 96 namespace remoting { |
90 | 97 |
91 HostService::HostService() : | 98 HostService::HostService() : |
92 console_session_id_(kInvalidSessionId), | 99 console_session_id_(kInvalidSessionId), |
93 run_routine_(&HostService::RunAsService), | 100 run_routine_(&HostService::RunAsService), |
94 service_status_handle_(0), | 101 service_status_handle_(0), |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 } | 164 } |
158 } | 165 } |
159 | 166 |
160 HostService* HostService::GetInstance() { | 167 HostService* HostService::GetInstance() { |
161 return Singleton<HostService>::get(); | 168 return Singleton<HostService>::get(); |
162 } | 169 } |
163 | 170 |
164 bool HostService::InitWithCommandLine(const CommandLine* command_line) { | 171 bool HostService::InitWithCommandLine(const CommandLine* command_line) { |
165 CommandLine::StringVector args = command_line->GetArgs(); | 172 CommandLine::StringVector args = command_line->GetArgs(); |
166 | 173 |
167 // Choose the action to perform. | 174 // Check if launch with elevation was requested. |
175 if (command_line->HasSwitch(kElevateSwitchName)) { | |
176 run_routine_ = &HostService::Elevate; | |
177 return true; | |
178 } | |
179 | |
168 if (!args.empty()) { | 180 if (!args.empty()) { |
169 if (args.size() > 1) { | 181 LOG(ERROR) << "No positional parameters expected."; |
170 LOG(ERROR) << "Invalid command line: more than one action requested."; | 182 return false; |
171 return false; | |
172 } | |
173 if (args[0] != kRunActionName) { | |
174 LOG(ERROR) << "Invalid command line: invalid action specified: " | |
175 << args[0]; | |
176 return false; | |
177 } | |
178 } | 183 } |
179 | 184 |
180 // Run interactively if needed. | 185 // Run interactively if needed. |
181 if (run_routine_ == &HostService::RunAsService && | 186 if (run_routine_ == &HostService::RunAsService && |
182 command_line->HasSwitch(kConsoleSwitchName)) { | 187 command_line->HasSwitch(kConsoleSwitchName)) { |
183 run_routine_ = &HostService::RunInConsole; | 188 run_routine_ = &HostService::RunInConsole; |
184 } | 189 } |
185 | 190 |
186 return true; | 191 return true; |
187 } | 192 } |
(...skipping 30 matching lines...) Expand all Loading... | |
218 | 223 |
219 #endif // !defined(REMOTING_MULTI_PROCESS) | 224 #endif // !defined(REMOTING_MULTI_PROCESS) |
220 | 225 |
221 // Run the service. | 226 // Run the service. |
222 message_loop->Run(); | 227 message_loop->Run(); |
223 | 228 |
224 // Release the control handler. | 229 // Release the control handler. |
225 stopped_event_.Signal(); | 230 stopped_event_.Signal(); |
226 } | 231 } |
227 | 232 |
233 int HostService::Elevate() { | |
234 // Get the name of the binary to launch. | |
235 FilePath binary = | |
236 CommandLine::ForCurrentProcess()->GetSwitchValuePath(kElevateSwitchName); | |
237 | |
238 // Create the child process command line by copying known switches from our | |
239 // command line. | |
240 CommandLine command_line(CommandLine::NO_PROGRAM); | |
241 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), | |
242 kCopiedSwitchNames, | |
243 _countof(kCopiedSwitchNames)); | |
244 CommandLine::StringType parameters = command_line.GetCommandLineString(); | |
245 | |
246 // Launch the child process requesting elevation. | |
247 SHELLEXECUTEINFO info; | |
248 memset(&info, 0, sizeof(info)); | |
249 info.cbSize = sizeof(info); | |
250 info.lpVerb = L"runas"; | |
251 info.lpFile = binary.value().c_str(); | |
252 info.lpParameters = parameters.c_str(); | |
253 info.nShow = SW_SHOWNORMAL; | |
254 | |
255 if (!ShellExecuteEx(&info)) { | |
256 return GetLastError(); | |
257 } | |
258 | |
259 return kSuccessExitCode; | |
260 } | |
261 | |
228 int HostService::RunAsService() { | 262 int HostService::RunAsService() { |
229 SERVICE_TABLE_ENTRYW dispatch_table[] = { | 263 SERVICE_TABLE_ENTRYW dispatch_table[] = { |
230 { const_cast<LPWSTR>(kWindowsServiceName), &HostService::ServiceMain }, | 264 { const_cast<LPWSTR>(kWindowsServiceName), &HostService::ServiceMain }, |
231 { NULL, NULL } | 265 { NULL, NULL } |
232 }; | 266 }; |
233 | 267 |
234 if (!StartServiceCtrlDispatcherW(dispatch_table)) { | 268 if (!StartServiceCtrlDispatcherW(dispatch_table)) { |
235 LOG_GETLASTERROR(ERROR) | 269 LOG_GETLASTERROR(ERROR) |
236 << "Failed to connect to the service control manager"; | 270 << "Failed to connect to the service control manager"; |
237 return kErrorExitCode; | 271 return kErrorExitCode; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 return 0; | 436 return 0; |
403 } | 437 } |
404 | 438 |
405 default: | 439 default: |
406 return DefWindowProc(hwnd, message, wparam, lparam); | 440 return DefWindowProc(hwnd, message, wparam, lparam); |
407 } | 441 } |
408 } | 442 } |
409 | 443 |
410 } // namespace remoting | 444 } // namespace remoting |
411 | 445 |
412 int main(int argc, char** argv) { | 446 int CALLBACK WinMain(HINSTANCE instance , |
Wez
2012/08/15 23:22:20
nit: remove the errant space after |instance|
alexeypa (please no reviews)
2012/08/15 23:55:50
Done.
| |
447 HINSTANCE previous_instance, | |
448 LPSTR raw_command_line, | |
449 int show_command) { | |
413 #ifdef OFFICIAL_BUILD | 450 #ifdef OFFICIAL_BUILD |
414 if (remoting::IsUsageStatsAllowed()) { | 451 if (remoting::IsUsageStatsAllowed()) { |
415 remoting::InitializeCrashReporting(); | 452 remoting::InitializeCrashReporting(); |
416 } | 453 } |
417 #endif // OFFICIAL_BUILD | 454 #endif // OFFICIAL_BUILD |
418 | 455 |
419 CommandLine::Init(argc, argv); | 456 // CommandLine::Init() ignores the passed |argc| and |argv| on Windows getting |
457 // the command line from GetCommandLineW(), so we can safely pass NULL here. | |
458 CommandLine::Init(0, NULL); | |
420 | 459 |
421 // This object instance is required by Chrome code (for example, | 460 // This object instance is required by Chrome code (for example, |
422 // FilePath, LazyInstance, MessageLoop). | 461 // FilePath, LazyInstance, MessageLoop). |
423 base::AtExitManager exit_manager; | 462 base::AtExitManager exit_manager; |
424 | 463 |
425 // Write logs to the application profile directory. | 464 // Write logs to the application profile directory. |
426 FilePath debug_log = remoting::GetConfigDir(). | 465 FilePath debug_log = remoting::GetConfigDir(). |
427 Append(FILE_PATH_LITERAL("debug.log")); | 466 Append(FILE_PATH_LITERAL("debug.log")); |
428 InitLogging(debug_log.value().c_str(), | 467 InitLogging(debug_log.value().c_str(), |
429 logging::LOG_ONLY_TO_FILE, | 468 logging::LOG_ONLY_TO_FILE, |
430 logging::DONT_LOCK_LOG_FILE, | 469 logging::DONT_LOCK_LOG_FILE, |
431 logging::APPEND_TO_OLD_LOG_FILE, | 470 logging::APPEND_TO_OLD_LOG_FILE, |
432 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); | 471 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); |
433 | 472 |
434 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 473 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
435 | |
436 if (command_line->HasSwitch(kHelpSwitchName) || | 474 if (command_line->HasSwitch(kHelpSwitchName) || |
437 command_line->HasSwitch(kQuestionSwitchName)) { | 475 command_line->HasSwitch(kQuestionSwitchName)) { |
438 usage(argv[0]); | 476 usage(command_line->GetProgram()); |
439 return kSuccessExitCode; | 477 return kSuccessExitCode; |
440 } | 478 } |
441 | 479 |
442 remoting::HostService* service = remoting::HostService::GetInstance(); | 480 remoting::HostService* service = remoting::HostService::GetInstance(); |
443 if (!service->InitWithCommandLine(command_line)) { | 481 if (!service->InitWithCommandLine(command_line)) { |
444 usage(argv[0]); | 482 usage(command_line->GetProgram()); |
445 return kUsageExitCode; | 483 return kUsageExitCode; |
446 } | 484 } |
447 | 485 |
448 return service->Run(); | 486 return service->Run(); |
449 } | 487 } |
OLD | NEW |