Chromium Code Reviews| 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 #include "cloud_print/service/win/cloud_print_service.h" | 5 #include "cloud_print/service/win/cloud_print_service.h" |
| 6 | 6 |
| 7 #include <atlsecurity.h> | 7 #define SECURITY_WIN32 |
| 8 #include <security.h> | |
| 9 | |
| 8 #include <iomanip> | 10 #include <iomanip> |
| 9 #include <iostream> | 11 #include <iostream> |
| 10 | 12 |
| 11 #include "base/at_exit.h" | 13 #include "base/at_exit.h" |
| 12 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 13 #include "base/file_path.h" | 15 #include "base/file_path.h" |
| 14 #include "base/file_util.h" | 16 #include "base/file_util.h" |
| 17 #include "base/guid.h" | |
| 15 #include "base/path_service.h" | 18 #include "base/path_service.h" |
| 16 #include "base/string_util.h" | 19 #include "base/string_util.h" |
| 20 #include "base/utf_string_conversions.h" | |
| 17 #include "base/win/scoped_handle.h" | 21 #include "base/win/scoped_handle.h" |
| 18 #include "chrome/installer/launcher_support/chrome_launcher_support.h" | 22 #include "chrome/installer/launcher_support/chrome_launcher_support.h" |
| 19 #include "cloud_print/service/service_state.h" | 23 #include "cloud_print/service/service_state.h" |
| 20 #include "cloud_print/service/service_switches.h" | 24 #include "cloud_print/service/service_switches.h" |
| 21 #include "cloud_print/service/win/chrome_launcher.h" | 25 #include "cloud_print/service/win/chrome_launcher.h" |
| 22 #include "cloud_print/service/win/local_security_policy.h" | 26 #include "cloud_print/service/win/local_security_policy.h" |
| 23 #include "cloud_print/service/win/resource.h" | 27 #include "cloud_print/service/win/resource.h" |
| 28 #include "printing/backend/print_backend.h" | |
| 24 | 29 |
| 25 namespace { | 30 namespace { |
| 26 | 31 |
| 32 const wchar_t kPrintersFileName[] = L"printers.txt"; | |
| 27 const wchar_t kServiceStateFileName[] = L"Service State"; | 33 const wchar_t kServiceStateFileName[] = L"Service State"; |
| 28 | 34 |
| 29 // The traits class for Windows Service. | 35 // The traits class for Windows Service. |
| 30 class ServiceHandleTraits { | 36 class ServiceHandleTraits { |
| 31 public: | 37 public: |
| 32 typedef SC_HANDLE Handle; | 38 typedef SC_HANDLE Handle; |
| 33 | 39 |
| 34 // Closes the handle. | 40 // Closes the handle. |
| 35 static bool CloseHandle(Handle handle) { | 41 static bool CloseHandle(Handle handle) { |
| 36 return ::CloseServiceHandle(handle) != FALSE; | 42 return ::CloseServiceHandle(handle) != FALSE; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 63 FilePath service_path; | 69 FilePath service_path; |
| 64 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 70 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
| 65 | 71 |
| 66 std::cout << "Usage: "; | 72 std::cout << "Usage: "; |
| 67 std::cout << service_path.BaseName().value(); | 73 std::cout << service_path.BaseName().value(); |
| 68 std::cout << " ["; | 74 std::cout << " ["; |
| 69 std::cout << "["; | 75 std::cout << "["; |
| 70 std::cout << "["; | 76 std::cout << "["; |
| 71 std::cout << " -" << kInstallSwitch; | 77 std::cout << " -" << kInstallSwitch; |
| 72 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; | 78 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; |
| 73 std::cout << " -" << kRunAsUser << "=USERNAME"; | |
| 74 std::cout << " -" << kRunAsPassword << "=PASSWORD"; | |
| 75 std::cout << " [ -" << kQuietSwitch << " ]"; | |
| 76 std::cout << "]"; | 79 std::cout << "]"; |
| 77 std::cout << "]"; | 80 std::cout << "]"; |
| 78 std::cout << " | -" << kUninstallSwitch; | 81 std::cout << " | -" << kUninstallSwitch; |
| 79 std::cout << " | -" << kStartSwitch; | 82 std::cout << " | -" << kStartSwitch; |
| 80 std::cout << " | -" << kStopSwitch; | 83 std::cout << " | -" << kStopSwitch; |
| 81 std::cout << " ]\n"; | 84 std::cout << " ]\n"; |
| 82 std::cout << "Manages cloud print windows service.\n\n"; | 85 std::cout << "Manages cloud print windows service.\n\n"; |
| 83 | 86 |
| 84 static const struct { | 87 static const struct { |
| 85 const char* name; | 88 const char* name; |
| 86 const char* description; | 89 const char* description; |
| 87 } kSwitchHelp[] = { | 90 } kSwitchHelp[] = { |
| 88 { kInstallSwitch, "Installs cloud print as service." }, | 91 { kInstallSwitch, "Installs cloud print as service." }, |
| 89 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, | 92 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, |
| 90 { kQuietSwitch, "Fails without questions if something wrong." }, | |
| 91 { kUninstallSwitch, "Uninstalls service." }, | 93 { kUninstallSwitch, "Uninstalls service." }, |
| 92 { kStartSwitch, "Starts service. May be combined with installation." }, | 94 { kStartSwitch, "Starts service. May be combined with installation." }, |
| 93 { kStopSwitch, "Stops service." }, | 95 { kStopSwitch, "Stops service." }, |
| 94 { kRunAsUser, "Windows user to run the service in form DOMAIN\\USERNAME. " | |
| 95 "Make sure user has access to printers." }, | |
| 96 { kRunAsPassword, "Password for windows user to run the service" }, | |
| 97 }; | 96 }; |
| 98 | 97 |
| 99 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { | 98 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { |
| 100 std::cout << std::setiosflags(std::ios::left); | 99 std::cout << std::setiosflags(std::ios::left); |
| 101 std::cout << " -" << std::setw(16) << kSwitchHelp[i].name; | 100 std::cout << " -" << std::setw(16) << kSwitchHelp[i].name; |
| 102 std::cout << kSwitchHelp[i].description << "\n"; | 101 std::cout << kSwitchHelp[i].description << "\n"; |
| 103 } | 102 } |
| 104 std::cout << "\n"; | 103 std::cout << "\n"; |
| 105 } | 104 } |
| 106 | 105 |
| 107 std::string GetOption(const std::string& name, const std::string& default, | 106 std::string GetOption(const std::string& name, const std::string& default, |
| 108 bool secure) { | 107 bool secure) { |
| 109 std::cout << "Input \'" << name << "\'"; | 108 std::cout << name; |
| 110 if (!default.empty()) { | 109 if (!default.empty()) { |
| 111 std::cout << ", press [ENTER] to keep '"; | 110 std::cout << ", press [ENTER] to keep '"; |
| 112 std::cout << default; | 111 std::cout << default; |
| 113 std::cout << "'"; | 112 std::cout << "'"; |
| 114 } | 113 } |
| 115 std::cout << ":"; | 114 std::cout << ": "; |
| 116 std::string tmp; | 115 std::string tmp; |
| 117 | 116 |
| 118 if (secure) { | 117 if (secure) { |
| 119 DWORD saved_mode = 0; | 118 DWORD saved_mode = 0; |
| 120 // Don't close. | 119 // Don't close. |
| 121 HANDLE stdin_handle = ::GetStdHandle(STD_INPUT_HANDLE); | 120 HANDLE stdin_handle = ::GetStdHandle(STD_INPUT_HANDLE); |
| 122 ::GetConsoleMode(stdin_handle, &saved_mode); | 121 ::GetConsoleMode(stdin_handle, &saved_mode); |
| 123 ::SetConsoleMode(stdin_handle, saved_mode & ~ENABLE_ECHO_INPUT); | 122 ::SetConsoleMode(stdin_handle, saved_mode & ~ENABLE_ECHO_INPUT); |
| 124 std::getline(std::cin, tmp); | 123 std::getline(std::cin, tmp); |
| 125 ::SetConsoleMode(stdin_handle, saved_mode); | 124 ::SetConsoleMode(stdin_handle, saved_mode); |
| 126 std::cout << "\n"; | 125 std::cout << "\n"; |
| 127 } else { | 126 } else { |
| 128 std::getline(std::cin, tmp); | 127 std::getline(std::cin, tmp); |
| 129 } | 128 } |
| 130 if (tmp.empty()) | 129 if (tmp.empty()) |
| 131 return default; | 130 return default; |
| 132 return tmp; | 131 return tmp; |
| 133 } | 132 } |
| 134 | 133 |
| 135 HRESULT WriteFileAsUser(const FilePath& path, const string16& user, | 134 bool AskUser(const std::string& request) { |
| 136 const char* data, int size) { | 135 for (;;) { |
| 137 ATL::CAccessToken token; | 136 std::cout << request << " [Y/n]:"; |
| 138 ATL::CAutoRevertImpersonation auto_revert(&token); | 137 std::string input; |
| 139 if (!user.empty()) { | 138 std::getline(std::cin, input); |
| 140 ATL::CAccessToken thread_token; | 139 StringToLowerASCII(&input); |
| 141 if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) { | 140 if (input.empty() || input == "y") { |
| 142 LOG(ERROR) << "Failed to open thread token."; | 141 return true; |
| 143 return HResultFromLastError(); | 142 } else if (input == "n") { |
| 144 } | 143 return false; |
| 144 } | |
| 145 } | |
| 146 } | |
| 145 | 147 |
| 146 ATL::CSid local_service; | 148 string16 GetCurrentUserName() { |
| 147 if (!local_service.LoadAccount(user.c_str())) { | 149 ULONG size = 0; |
| 148 LOG(ERROR) << "Failed create SID."; | 150 string16 result; |
| 149 return HResultFromLastError(); | 151 ::GetUserNameEx(::NameSamCompatible, NULL, &size); |
| 150 } | 152 result.resize(size); |
| 151 | 153 if (result.empty()) |
| 152 ATL::CTokenGroups group; | 154 return result; |
| 153 group.Add(local_service, 0); | 155 if (!::GetUserNameEx(::NameSamCompatible, &result[0], &size)) |
| 154 | 156 result.clear(); |
| 155 const ATL::CTokenGroups empty_group; | 157 result.resize(size); |
| 156 if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) { | 158 return result; |
| 157 LOG(ERROR) << "Failed to create restricted token for " << user << "."; | |
| 158 return HResultFromLastError(); | |
| 159 } | |
| 160 | |
| 161 if (!token.Impersonate()) { | |
| 162 LOG(ERROR) << "Failed to impersonate " << user << "."; | |
| 163 return HResultFromLastError(); | |
| 164 } | |
| 165 } | |
| 166 if (file_util::WriteFile(path, data, size) != size) { | |
| 167 LOG(ERROR) << "Failed to write file " << path.value() << "."; | |
| 168 return HResultFromLastError(); | |
| 169 } | |
| 170 return S_OK; | |
| 171 } | 159 } |
| 172 | 160 |
| 173 } // namespace | 161 } // namespace |
| 174 | 162 |
| 175 class CloudPrintServiceModule | 163 class CloudPrintServiceModule |
| 176 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { | 164 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { |
| 177 public: | 165 public: |
| 178 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, | 166 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, |
| 179 IDS_SERVICENAME> Base; | 167 IDS_SERVICENAME> Base; |
| 180 | 168 |
| 181 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, | 169 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, |
| 182 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") | 170 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") |
| 183 | 171 |
| 172 CloudPrintServiceModule() : detect_printers_(false) { | |
| 173 } | |
| 174 | |
| 184 HRESULT InitializeSecurity() { | 175 HRESULT InitializeSecurity() { |
| 185 // TODO(gene): Check if we need to call CoInitializeSecurity and provide | 176 // TODO(gene): Check if we need to call CoInitializeSecurity and provide |
| 186 // the appropriate security settings for service. | 177 // the appropriate security settings for service. |
| 187 return S_OK; | 178 return S_OK; |
| 188 } | 179 } |
| 189 | 180 |
| 190 HRESULT InstallService(const string16& user, const string16& password) { | 181 HRESULT InstallService(const string16& user, |
| 182 const string16& password, | |
| 183 const char* run_switch) { | |
| 191 using namespace chrome_launcher_support; | 184 using namespace chrome_launcher_support; |
| 192 | 185 |
| 193 // TODO(vitalybuka): consider "lite" version if we don't want unregister | 186 // TODO(vitalybuka): consider "lite" version if we don't want unregister |
| 194 // printers here. | 187 // printers here. |
| 195 HRESULT hr = UninstallService(); | 188 HRESULT hr = UninstallService(); |
| 196 if (FAILED(hr)) | 189 if (FAILED(hr)) |
| 197 return hr; | 190 return hr; |
| 198 | 191 |
| 199 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { | 192 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { |
| 200 LOG(WARNING) << "Found no Chrome installed for all users."; | 193 LOG(WARNING) << "Found no Chrome installed for all users."; |
| 201 } | 194 } |
| 202 | 195 |
| 203 hr = UpdateRegistryAppId(true); | 196 hr = UpdateRegistryAppId(true); |
| 204 if (FAILED(hr)) | 197 if (FAILED(hr)) |
| 205 return hr; | 198 return hr; |
| 206 | 199 |
| 207 FilePath service_path; | 200 FilePath service_path; |
| 208 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 201 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
| 209 CommandLine command_line(service_path); | 202 CommandLine command_line(service_path); |
| 210 command_line.AppendSwitch(kServiceSwitch); | 203 command_line.AppendSwitch(run_switch); |
| 211 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); | 204 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); |
| 212 | 205 |
| 213 LocalSecurityPolicy local_security_policy; | 206 LocalSecurityPolicy local_security_policy; |
| 214 if (local_security_policy.Open()) { | 207 if (local_security_policy.Open()) { |
| 215 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { | 208 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { |
| 216 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; | 209 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; |
| 217 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { | 210 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { |
| 218 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; | 211 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; |
| 219 LOG(ERROR) << "Make sure you can run the service with this user."; | 212 LOG(ERROR) << "Make sure you can run the service as " << user << "."; |
| 220 } | 213 } |
| 221 } | 214 } |
| 222 } else { | 215 } else { |
| 223 LOG(ERROR) << "Failed to open security policy."; | 216 LOG(ERROR) << "Failed to open security policy."; |
| 224 } | 217 } |
| 225 | 218 |
| 226 ServiceHandle scm; | 219 ServiceHandle scm; |
| 227 hr = OpenServiceManager(&scm); | 220 hr = OpenServiceManager(&scm); |
| 228 if (FAILED(hr)) | 221 if (FAILED(hr)) |
| 229 return hr; | 222 return hr; |
| 230 | 223 |
| 231 ServiceHandle service( | 224 ServiceHandle service( |
| 232 ::CreateService( | 225 ::CreateService( |
| 233 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, | 226 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
| 234 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, | 227 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
| 235 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, | 228 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, |
| 236 user.empty() ? NULL : user.c_str(), | 229 user.empty() ? NULL : user.c_str(), |
| 237 password.empty() ? NULL : password.c_str())); | 230 password.empty() ? NULL : password.c_str())); |
| 238 | 231 |
| 239 if (!service.IsValid()) | 232 if (!service.IsValid()) { |
| 233 LOG(ERROR) << "Failed to install service as " << user << "."; | |
| 240 return HResultFromLastError(); | 234 return HResultFromLastError(); |
| 235 } | |
| 241 | 236 |
| 242 return S_OK; | 237 return S_OK; |
| 243 } | 238 } |
| 244 | 239 |
| 245 HRESULT UninstallService() { | 240 HRESULT UninstallService() { |
| 241 StopService(); | |
| 246 if (!Uninstall()) | 242 if (!Uninstall()) |
| 247 return E_FAIL; | 243 return E_FAIL; |
| 248 return UpdateRegistryAppId(false); | 244 return UpdateRegistryAppId(false); |
| 249 } | 245 } |
| 250 | 246 |
| 251 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { | 247 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { |
| 252 CHECK(pnRetCode); | 248 CHECK(pnRetCode); |
| 253 CommandLine command_line(CommandLine::NO_PROGRAM); | 249 CommandLine command_line(CommandLine::NO_PROGRAM); |
| 254 command_line.ParseFromString(lpCmdLine); | 250 command_line.ParseFromString(lpCmdLine); |
| 255 bool is_service = false; | 251 bool is_service = false; |
| 256 *pnRetCode = ParseCommandLine(command_line, &is_service); | 252 *pnRetCode = ParseCommandLine(command_line, &is_service); |
| 257 if (FAILED(*pnRetCode)) { | 253 if (FAILED(*pnRetCode)) { |
| 258 LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << | 254 LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << |
| 259 std::setbase(16) << *pnRetCode; | 255 std::setbase(16) << *pnRetCode; |
| 260 } | 256 } |
| 261 return is_service; | 257 return is_service; |
| 262 } | 258 } |
| 263 | 259 |
| 264 HRESULT PreMessageLoop(int nShowCmd) { | 260 HRESULT PreMessageLoop(int nShowCmd) { |
| 265 HRESULT hr = Base::PreMessageLoop(nShowCmd); | 261 HRESULT hr = Base::PreMessageLoop(nShowCmd); |
| 266 if (FAILED(hr)) | 262 if (FAILED(hr)) |
| 267 return hr; | 263 return hr; |
| 268 | 264 |
| 269 hr = StartConnector(); | 265 if (detect_printers_) { |
| 270 if (FAILED(hr)) | 266 hr = DetectPrinters(); |
| 271 return hr; | 267 if (FAILED(hr)) |
| 268 return hr; | |
| 269 return S_FALSE; | |
|
gene
2012/09/13 18:40:09
nit: Could you please a small comment why we retur
Vitaly Buka (NO REVIEWS)
2012/09/13 20:01:52
Done.
| |
| 270 } else { | |
| 271 hr = StartConnector(); | |
| 272 if (FAILED(hr)) | |
| 273 return hr; | |
| 274 } | |
| 272 | 275 |
| 273 LogEvent(_T("Service started/resumed")); | 276 LogEvent(_T("Service started/resumed")); |
| 274 SetServiceStatus(SERVICE_RUNNING); | 277 SetServiceStatus(SERVICE_RUNNING); |
| 275 | 278 |
| 276 return hr; | 279 return hr; |
| 277 } | 280 } |
| 278 | 281 |
| 279 HRESULT PostMessageLoop() { | 282 HRESULT PostMessageLoop() { |
| 280 StopConnector(); | 283 StopConnector(); |
| 281 return Base::PostMessageLoop(); | 284 return Base::PostMessageLoop(); |
| 282 } | 285 } |
| 283 | 286 |
| 284 private: | 287 private: |
| 285 HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) { | 288 HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) { |
| 286 if (!is_service) | 289 if (!is_service) |
| 287 return E_INVALIDARG; | 290 return E_INVALIDARG; |
| 288 *is_service = false; | 291 *is_service = false; |
| 289 | 292 |
| 290 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); | 293 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); |
| 291 if (command_line.HasSwitch(kStopSwitch)) | 294 if (command_line.HasSwitch(kStopSwitch)) |
| 292 return StopService(); | 295 return StopService(); |
| 293 | 296 |
| 294 if (command_line.HasSwitch(kUninstallSwitch)) | 297 if (command_line.HasSwitch(kUninstallSwitch)) |
| 295 return UninstallService(); | 298 return UninstallService(); |
| 296 | 299 |
| 297 if (command_line.HasSwitch(kInstallSwitch)) { | 300 if (command_line.HasSwitch(kInstallSwitch)) { |
| 298 if (!command_line.HasSwitch(kUserDataDirSwitch) || | 301 if (!command_line.HasSwitch(kUserDataDirSwitch)) { |
| 299 !command_line.HasSwitch(kRunAsUser) || | |
| 300 !command_line.HasSwitch(kRunAsPassword)) { | |
| 301 InvalidUsage(); | 302 InvalidUsage(); |
| 302 return S_FALSE; | 303 return S_FALSE; |
| 303 } | 304 } |
| 304 | 305 |
| 305 HRESULT hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); | 306 string16 run_as_user; |
| 307 string16 run_as_password; | |
| 308 SelectWindowsAccount(&run_as_user, &run_as_password); | |
| 309 | |
| 310 HRESULT hr = SetupServiceState(); | |
| 306 if (FAILED(hr)) | 311 if (FAILED(hr)) |
| 307 return hr; | 312 return hr; |
| 308 | 313 |
| 309 CommandLine::StringType run_as_user = | 314 hr = InstallService(run_as_user.c_str(), run_as_password.c_str(), |
| 310 command_line.GetSwitchValueNative(kRunAsUser); | 315 kServiceSwitch); |
| 311 CommandLine::StringType run_as_password = | |
| 312 command_line.GetSwitchValueNative(kRunAsPassword); | |
| 313 | |
| 314 hr = ValidateUserDataDir(run_as_user.c_str()); | |
| 315 | |
| 316 hr = InstallService(run_as_user.c_str(), run_as_password.c_str()); | |
| 317 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) | 316 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) |
| 318 return StartService(); | 317 return StartService(); |
| 319 | 318 |
| 320 return hr; | 319 return hr; |
| 321 } | 320 } |
| 322 | 321 |
| 323 if (command_line.HasSwitch(kStartSwitch)) | 322 if (command_line.HasSwitch(kStartSwitch)) |
| 324 return StartService(); | 323 return StartService(); |
| 325 | 324 |
| 326 if (command_line.HasSwitch(kServiceSwitch)) { | 325 if (command_line.HasSwitch(kServiceSwitch) || |
| 326 command_line.HasSwitch(kPrintersSwitch)) { | |
| 327 *is_service = true; | 327 *is_service = true; |
| 328 detect_printers_ = command_line.HasSwitch(kPrintersSwitch); | |
| 328 return S_OK; | 329 return S_OK; |
| 329 } | 330 } |
| 330 | 331 |
| 331 if (command_line.HasSwitch(kConsoleSwitch)) { | 332 if (command_line.HasSwitch(kConsoleSwitch)) { |
| 332 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); | 333 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); |
| 333 HRESULT hr = Run(); | 334 HRESULT hr = Run(); |
| 334 ::SetConsoleCtrlHandler(NULL, FALSE); | 335 ::SetConsoleCtrlHandler(NULL, FALSE); |
| 335 return hr; | 336 return hr; |
| 336 } | 337 } |
| 337 | 338 |
| 338 InvalidUsage(); | 339 InvalidUsage(); |
| 339 return S_FALSE; | 340 return S_FALSE; |
| 340 } | 341 } |
| 341 | 342 |
| 342 HRESULT ValidateUserDataDir(const string16& user) { | 343 void SelectWindowsAccount(string16* run_as_user, |
| 343 FilePath temp_file; | 344 string16* run_as_password) { |
| 344 const char some_data[] = "1234"; | 345 if (!run_as_user || !run_as_password) |
|
gene
2012/09/13 18:40:09
nit: remove this if?
I would rather crash (assert
Vitaly Buka (NO REVIEWS)
2012/09/13 20:01:52
Done.
| |
| 345 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) | 346 return; |
| 346 return E_FAIL; | 347 *run_as_user = GetCurrentUserName(); |
| 347 HRESULT hr = WriteFileAsUser(temp_file, user, some_data, | 348 for (;;) { |
| 348 sizeof(some_data)); | 349 std::cout << "\nPlease provide Windows account to run service.\n"; |
| 349 if (FAILED(hr)) { | 350 *run_as_user = ASCIIToWide(GetOption("Account as DOMAIN\\USERNAME", |
| 350 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << | 351 WideToASCII(*run_as_user), false)); |
| 351 user << "\' has full access to \'" << | 352 *run_as_password = ASCIIToWide(GetOption("Password", "", true)); |
| 352 user_data_dir_.value() << "\'."; | 353 |
| 354 FilePath printers_filename(user_data_dir_); | |
| 355 printers_filename = printers_filename.Append(kPrintersFileName); | |
| 356 | |
| 357 file_util::Delete(printers_filename, false); | |
| 358 if (FAILED(InstallService(run_as_user->c_str(), | |
| 359 run_as_password->c_str(), | |
| 360 kPrintersSwitch))) { | |
| 361 continue; | |
|
gene
2012/09/13 18:40:09
Any consistent failures in InstallService, StartSe
Vitaly Buka (NO REVIEWS)
2012/09/13 20:01:52
It's console app so it could be stopped with Ctrl+
| |
| 362 } | |
| 363 if (FAILED(StartService())) { | |
| 364 LOG(ERROR) << "Failed to start service as " << *run_as_user << "."; | |
| 365 continue; | |
| 366 } | |
| 367 UninstallService(); | |
| 368 if (!file_util::PathExists(printers_filename)) { | |
| 369 LOG(ERROR) << "Service can't create " << printers_filename.value(); | |
| 370 continue; | |
| 371 } | |
| 372 | |
| 373 std::string printers; | |
| 374 file_util::ReadFileToString(printers_filename, &printers); | |
| 375 std::cout << "\nPrinters available for " << run_as_user << ":\n"; | |
| 376 std::cout << printers << "\n"; | |
| 377 file_util::Delete(printers_filename, false); | |
| 378 | |
| 379 if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?")) | |
| 380 return; | |
| 353 } | 381 } |
| 354 file_util::Delete(temp_file, false); | |
| 355 return hr; | |
| 356 } | 382 } |
| 357 | 383 |
| 358 HRESULT ProcessServiceState(bool quiet) { | 384 HRESULT SetupServiceState() { |
| 359 FilePath file = user_data_dir_.Append(kServiceStateFileName); | 385 FilePath file = user_data_dir_.Append(kServiceStateFileName); |
| 360 | 386 |
| 361 for (;;) { | 387 for (;;) { |
| 362 std::string contents; | 388 std::string contents; |
| 363 ServiceState service_state; | 389 ServiceState service_state; |
| 364 | 390 |
| 365 bool is_valid = file_util::ReadFileToString(file, &contents) && | 391 bool is_valid = file_util::ReadFileToString(file, &contents) && |
| 366 service_state.FromString(contents); | 392 service_state.FromString(contents); |
| 367 | 393 |
| 368 if (!quiet) { | 394 std::cout << "\nFile '" << file.value() << "' content:\n"; |
| 369 std::cout << "\n"; | 395 std::cout << contents << "\n"; |
| 370 std::cout << file.value() << ":\n"; | |
| 371 std::cout << contents << "\n"; | |
| 372 } | |
| 373 | 396 |
| 374 if (!is_valid) | 397 if (!is_valid) |
| 375 LOG(ERROR) << "Invalid file: " << file.value(); | 398 LOG(ERROR) << "Invalid file: " << file.value(); |
| 376 | 399 |
| 377 if (quiet) | |
| 378 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID); | |
| 379 | |
| 380 if (!contents.empty()) { | 400 if (!contents.empty()) { |
| 381 std::cout << "Do you want to use this file [y/n]:"; | 401 if (AskUser("Do you want to use '" + WideToASCII(file.value()) + "'")) { |
| 382 for (;;) { | 402 return S_OK; |
| 383 std::string input; | 403 } else { |
| 384 std::getline(std::cin, input); | 404 is_valid = false; |
| 385 StringToLowerASCII(&input); | |
| 386 if (input == "y") { | |
| 387 return S_OK; | |
| 388 } else if (input == "n") { | |
| 389 is_valid = false; | |
| 390 break; | |
| 391 } | |
| 392 } | 405 } |
| 393 } | 406 } |
| 394 | 407 |
| 395 while (!is_valid) { | 408 while (!is_valid) { |
| 409 std::cout << "\nPlease provide Cloud Print Settings.\n"; | |
| 396 std::string email = GetOption("email", service_state.email(), false); | 410 std::string email = GetOption("email", service_state.email(), false); |
| 397 std::string password = GetOption("password", "", true); | 411 std::string password = GetOption("password", "", true); |
| 398 std::string proxy_id = GetOption("connector_id", | 412 std::string proxy_id = service_state.proxy_id(); |
| 399 service_state.proxy_id(), false); | 413 if (proxy_id.empty()) |
| 414 proxy_id = base::GenerateGUID(); | |
| 415 proxy_id = GetOption("connector_id", proxy_id, false); | |
| 400 is_valid = service_state.Configure(email, password, proxy_id); | 416 is_valid = service_state.Configure(email, password, proxy_id); |
| 401 if (is_valid) { | 417 if (is_valid) { |
| 402 std::string new_contents = service_state.ToString(); | 418 std::string new_contents = service_state.ToString(); |
| 403 if (new_contents != contents) { | 419 if (new_contents != contents) { |
| 404 size_t written = file_util::WriteFile(file, new_contents.c_str(), | 420 size_t written = file_util::WriteFile(file, new_contents.c_str(), |
| 405 new_contents.size()); | 421 new_contents.size()); |
| 406 if (written != new_contents.size()) { | 422 if (written != new_contents.size()) { |
| 407 LOG(ERROR) << "Failed to write file " << file.value() << "."; | 423 LOG(ERROR) << "Failed to write file " << file.value() << "."; |
| 408 return HResultFromLastError(); | 424 return HResultFromLastError(); |
| 409 } | 425 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 HRESULT hr = OpenService(SERVICE_START, &service); | 464 HRESULT hr = OpenService(SERVICE_START, &service); |
| 449 if (FAILED(hr)) | 465 if (FAILED(hr)) |
| 450 return hr; | 466 return hr; |
| 451 if (!::StartService(service, 0, NULL)) | 467 if (!::StartService(service, 0, NULL)) |
| 452 return HResultFromLastError(); | 468 return HResultFromLastError(); |
| 453 return S_OK; | 469 return S_OK; |
| 454 } | 470 } |
| 455 | 471 |
| 456 HRESULT StopService() { | 472 HRESULT StopService() { |
| 457 ServiceHandle service; | 473 ServiceHandle service; |
| 458 HRESULT hr = OpenService(SERVICE_STOP, &service); | 474 HRESULT hr = OpenService(SERVICE_STOP | SERVICE_QUERY_STATUS, &service); |
| 459 if (FAILED(hr)) | 475 if (FAILED(hr)) |
| 460 return hr; | 476 return hr; |
| 461 SERVICE_STATUS status = {0}; | 477 SERVICE_STATUS status = {0}; |
| 462 if (!::ControlService(service, SERVICE_CONTROL_STOP, &status)) | 478 if (!::ControlService(service, SERVICE_CONTROL_STOP, &status)) |
| 463 return HResultFromLastError(); | 479 return HResultFromLastError(); |
| 480 while (::QueryServiceStatus(service, &status) && | |
| 481 status.dwCurrentState > SERVICE_STOPPED) { | |
| 482 Sleep(500); | |
| 483 } | |
| 464 return S_OK; | 484 return S_OK; |
| 465 } | 485 } |
| 466 | 486 |
| 487 HRESULT DetectPrinters() { | |
| 488 FilePath printers_filename(user_data_dir_); | |
| 489 printers_filename = printers_filename.Append(kPrintersFileName); | |
| 490 std::string printers; | |
| 491 scoped_refptr<printing::PrintBackend> backend( | |
| 492 printing::PrintBackend::CreateInstance(NULL)); | |
| 493 printing::PrinterList printer_list; | |
| 494 backend->EnumeratePrinters(&printer_list); | |
| 495 for (size_t i = 0; i < printer_list.size(); ++i) { | |
| 496 printers += printer_list[i].printer_name; | |
| 497 printers += "\n"; | |
| 498 } | |
| 499 file_util::WriteFile(printers_filename, printers.c_str(), printers.size()); | |
| 500 return S_OK; | |
| 501 } | |
| 502 | |
| 467 HRESULT StartConnector() { | 503 HRESULT StartConnector() { |
| 468 chrome_.reset(new ChromeLauncher(user_data_dir_)); | 504 chrome_.reset(new ChromeLauncher(user_data_dir_)); |
| 469 return chrome_->Start() ? S_OK : E_FAIL; | 505 return chrome_->Start() ? S_OK : E_FAIL; |
| 470 } | 506 } |
| 471 | 507 |
| 472 void StopConnector() { | 508 void StopConnector() { |
| 473 chrome_->Stop(); | 509 if (chrome_.get()) { |
| 474 chrome_.reset(); | 510 chrome_->Stop(); |
| 511 chrome_.reset(); | |
| 512 } | |
| 475 } | 513 } |
| 476 | 514 |
| 477 static BOOL WINAPI ConsoleCtrlHandler(DWORD type); | 515 static BOOL WINAPI ConsoleCtrlHandler(DWORD type); |
| 478 | 516 |
| 517 bool detect_printers_; | |
| 479 FilePath user_data_dir_; | 518 FilePath user_data_dir_; |
| 480 scoped_ptr<ChromeLauncher> chrome_; | 519 scoped_ptr<ChromeLauncher> chrome_; |
| 481 }; | 520 }; |
| 482 | 521 |
| 483 CloudPrintServiceModule _AtlModule; | 522 CloudPrintServiceModule _AtlModule; |
| 484 | 523 |
| 485 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { | 524 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { |
| 486 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); | 525 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); |
| 487 return TRUE; | 526 return TRUE; |
| 488 } | 527 } |
| 489 | 528 |
| 490 int main() { | 529 int main() { |
| 491 base::AtExitManager at_exit; | 530 base::AtExitManager at_exit; |
| 492 return _AtlModule.WinMain(0); | 531 return _AtlModule.WinMain(0); |
| 493 } | 532 } |
| OLD | NEW |