summaryrefslogtreecommitdiffstats
path: root/cloud_print
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-14 02:36:20 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-14 02:36:20 +0000
commitf5305d84292ddfa2dbd7a7512dd58d096fc7547d (patch)
tree8b04a32a69334e6d2f0bd3ed81c38c4a75d16a85 /cloud_print
parent5b9d6c34051ad68bef7a859af2db8a7f60968277 (diff)
downloadchromium_src-f5305d84292ddfa2dbd7a7512dd58d096fc7547d.zip
chromium_src-f5305d84292ddfa2dbd7a7512dd58d096fc7547d.tar.gz
chromium_src-f5305d84292ddfa2dbd7a7512dd58d096fc7547d.tar.bz2
Improved cloud print service installation.
Removed quiet option. Prompt for Windows user/password instead of switches. Show printers available for selected account. Check permissions and available printers in real system process. Generate guid as proxy_id if it's empty. BUG=148913 Review URL: https://chromiumcodereview.appspot.com/10919262 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156719 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r--cloud_print/DEPS1
-rw-r--r--cloud_print/service/service.gyp4
-rw-r--r--cloud_print/service/service_switches.cc4
-rw-r--r--cloud_print/service/service_switches.h7
-rw-r--r--cloud_print/service/win/cloud_print_service.cc244
5 files changed, 149 insertions, 111 deletions
diff --git a/cloud_print/DEPS b/cloud_print/DEPS
index 75fed87..350c845 100644
--- a/cloud_print/DEPS
+++ b/cloud_print/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+chrome/installer/launcher_support",
"+grit", # For generated headers
"+net",
+ "+printing",
]
diff --git a/cloud_print/service/service.gyp b/cloud_print/service/service.gyp
index 4df759a..1a30919 100644
--- a/cloud_print/service/service.gyp
+++ b/cloud_print/service/service.gyp
@@ -18,6 +18,7 @@
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/build/temp_gyp/googleurl.gyp:googleurl',
'<(DEPTH)/net/net.gyp:net',
+ '<(DEPTH)/printing/printing.gyp:printing',
],
'sources': [
'service_state.cc',
@@ -64,6 +65,9 @@
'VCLinkerTool': {
'SubSystem': '1', # Set /SUBSYSTEM:CONSOLE
'UACExecutionLevel': '2', # /level='requireAdministrator'
+ 'AdditionalDependencies': [
+ 'secur32.lib',
+ ],
},
},
},
diff --git a/cloud_print/service/service_switches.cc b/cloud_print/service/service_switches.cc
index 18602a4..823f031 100644
--- a/cloud_print/service/service_switches.cc
+++ b/cloud_print/service/service_switches.cc
@@ -7,9 +7,7 @@
const char kChromeTypeSwitch[] = "type";
const char kConsoleSwitch[] = "console";
const char kInstallSwitch[] = "install";
-const char kQuietSwitch[] = "quiet";
-const char kRunAsPassword[] = "run-as-password";
-const char kRunAsUser[] = "run-as-user";
+const char kPrintersSwitch[] = "printers";
const char kServiceSwitch[] = "service";
const char kStartSwitch[] = "start";
const char kStopSwitch[] = "stop";
diff --git a/cloud_print/service/service_switches.h b/cloud_print/service/service_switches.h
index 836d0e5..dfd6a78 100644
--- a/cloud_print/service/service_switches.h
+++ b/cloud_print/service/service_switches.h
@@ -8,11 +8,8 @@
extern const char kChromeTypeSwitch[];
extern const char kConsoleSwitch[];
extern const char kInstallSwitch[];
-extern const char kQuietSwitch[];
-extern const char kRunAsPassword[];
-extern const char kRunAsUser[];
-extern const char kServiceSwitch[];
-extern const char kStartSwitch[];
+extern const char kPrintersSwitch[];
+extern const char kServiceSwitch[];extern const char kStartSwitch[];
extern const char kStopSwitch[];
extern const char kUninstallSwitch[];
extern const char kUserDataDirSwitch[];
diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc
index eb210ff6..02b2daf 100644
--- a/cloud_print/service/win/cloud_print_service.cc
+++ b/cloud_print/service/win/cloud_print_service.cc
@@ -4,7 +4,9 @@
#include "cloud_print/service/win/cloud_print_service.h"
-#include <atlsecurity.h>
+#define SECURITY_WIN32
+#include <security.h>
+
#include <iomanip>
#include <iostream>
@@ -12,8 +14,10 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/guid.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/win/scoped_handle.h"
#include "chrome/installer/launcher_support/chrome_launcher_support.h"
#include "cloud_print/service/service_state.h"
@@ -21,9 +25,11 @@
#include "cloud_print/service/win/chrome_launcher.h"
#include "cloud_print/service/win/local_security_policy.h"
#include "cloud_print/service/win/resource.h"
+#include "printing/backend/print_backend.h"
namespace {
+const wchar_t kPrintersFileName[] = L"printers.txt";
const wchar_t kServiceStateFileName[] = L"Service State";
// The traits class for Windows Service.
@@ -70,9 +76,6 @@ void InvalidUsage() {
std::cout << "[";
std::cout << " -" << kInstallSwitch;
std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY";
- std::cout << " -" << kRunAsUser << "=USERNAME";
- std::cout << " -" << kRunAsPassword << "=PASSWORD";
- std::cout << " [ -" << kQuietSwitch << " ]";
std::cout << "]";
std::cout << "]";
std::cout << " | -" << kUninstallSwitch;
@@ -87,13 +90,9 @@ void InvalidUsage() {
} kSwitchHelp[] = {
{ kInstallSwitch, "Installs cloud print as service." },
{ kUserDataDirSwitch, "User data directory with \"Service State\" file." },
- { kQuietSwitch, "Fails without questions if something wrong." },
{ kUninstallSwitch, "Uninstalls service." },
{ kStartSwitch, "Starts service. May be combined with installation." },
{ kStopSwitch, "Stops service." },
- { kRunAsUser, "Windows user to run the service in form DOMAIN\\USERNAME. "
- "Make sure user has access to printers." },
- { kRunAsPassword, "Password for windows user to run the service" },
};
for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) {
@@ -106,13 +105,13 @@ void InvalidUsage() {
std::string GetOption(const std::string& name, const std::string& default,
bool secure) {
- std::cout << "Input \'" << name << "\'";
+ std::cout << name;
if (!default.empty()) {
std::cout << ", press [ENTER] to keep '";
std::cout << default;
std::cout << "'";
}
- std::cout << ":";
+ std::cout << ": ";
std::string tmp;
if (secure) {
@@ -132,42 +131,31 @@ std::string GetOption(const std::string& name, const std::string& default,
return tmp;
}
-HRESULT WriteFileAsUser(const FilePath& path, const string16& user,
- const char* data, int size) {
- ATL::CAccessToken token;
- ATL::CAutoRevertImpersonation auto_revert(&token);
- if (!user.empty()) {
- ATL::CAccessToken thread_token;
- if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) {
- LOG(ERROR) << "Failed to open thread token.";
- return HResultFromLastError();
- }
-
- ATL::CSid local_service;
- if (!local_service.LoadAccount(user.c_str())) {
- LOG(ERROR) << "Failed create SID.";
- return HResultFromLastError();
- }
-
- ATL::CTokenGroups group;
- group.Add(local_service, 0);
-
- const ATL::CTokenGroups empty_group;
- if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) {
- LOG(ERROR) << "Failed to create restricted token for " << user << ".";
- return HResultFromLastError();
- }
-
- if (!token.Impersonate()) {
- LOG(ERROR) << "Failed to impersonate " << user << ".";
- return HResultFromLastError();
- }
+bool AskUser(const std::string& request) {
+ for (;;) {
+ std::cout << request << " [Y/n]:";
+ std::string input;
+ std::getline(std::cin, input);
+ StringToLowerASCII(&input);
+ if (input.empty() || input == "y") {
+ return true;
+ } else if (input == "n") {
+ return false;
}
- if (file_util::WriteFile(path, data, size) != size) {
- LOG(ERROR) << "Failed to write file " << path.value() << ".";
- return HResultFromLastError();
- }
- return S_OK;
+ }
+}
+
+string16 GetCurrentUserName() {
+ ULONG size = 0;
+ string16 result;
+ ::GetUserNameEx(::NameSamCompatible, NULL, &size);
+ result.resize(size);
+ if (result.empty())
+ return result;
+ if (!::GetUserNameEx(::NameSamCompatible, &result[0], &size))
+ result.clear();
+ result.resize(size);
+ return result;
}
} // namespace
@@ -181,13 +169,18 @@ class CloudPrintServiceModule
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE,
"{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}")
+ CloudPrintServiceModule() : detect_printers_(false) {
+ }
+
HRESULT InitializeSecurity() {
// TODO(gene): Check if we need to call CoInitializeSecurity and provide
// the appropriate security settings for service.
return S_OK;
}
- HRESULT InstallService(const string16& user, const string16& password) {
+ HRESULT InstallService(const string16& user,
+ const string16& password,
+ const char* run_switch) {
using namespace chrome_launcher_support;
// TODO(vitalybuka): consider "lite" version if we don't want unregister
@@ -207,7 +200,7 @@ class CloudPrintServiceModule
FilePath service_path;
CHECK(PathService::Get(base::FILE_EXE, &service_path));
CommandLine command_line(service_path);
- command_line.AppendSwitch(kServiceSwitch);
+ command_line.AppendSwitch(run_switch);
command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_);
LocalSecurityPolicy local_security_policy;
@@ -216,7 +209,7 @@ class CloudPrintServiceModule
LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user;
if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) {
LOG(ERROR) << "Failed to set" << kSeServiceLogonRight;
- LOG(ERROR) << "Make sure you can run the service with this user.";
+ LOG(ERROR) << "Make sure you can run the service as " << user << ".";
}
}
} else {
@@ -236,13 +229,16 @@ class CloudPrintServiceModule
user.empty() ? NULL : user.c_str(),
password.empty() ? NULL : password.c_str()));
- if (!service.IsValid())
+ if (!service.IsValid()) {
+ LOG(ERROR) << "Failed to install service as " << user << ".";
return HResultFromLastError();
+ }
return S_OK;
}
HRESULT UninstallService() {
+ StopService();
if (!Uninstall())
return E_FAIL;
return UpdateRegistryAppId(false);
@@ -266,9 +262,17 @@ class CloudPrintServiceModule
if (FAILED(hr))
return hr;
- hr = StartConnector();
- if (FAILED(hr))
- return hr;
+ if (detect_printers_) {
+ hr = DetectPrinters();
+ if (FAILED(hr))
+ return hr;
+ // Don't run message loop and stop service.
+ return S_FALSE;
+ } else {
+ hr = StartConnector();
+ if (FAILED(hr))
+ return hr;
+ }
LogEvent(_T("Service started/resumed"));
SetServiceStatus(SERVICE_RUNNING);
@@ -295,25 +299,21 @@ class CloudPrintServiceModule
return UninstallService();
if (command_line.HasSwitch(kInstallSwitch)) {
- if (!command_line.HasSwitch(kUserDataDirSwitch) ||
- !command_line.HasSwitch(kRunAsUser) ||
- !command_line.HasSwitch(kRunAsPassword)) {
+ if (!command_line.HasSwitch(kUserDataDirSwitch)) {
InvalidUsage();
return S_FALSE;
}
- HRESULT hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch));
+ string16 run_as_user;
+ string16 run_as_password;
+ SelectWindowsAccount(&run_as_user, &run_as_password);
+
+ HRESULT hr = SetupServiceState();
if (FAILED(hr))
return hr;
- CommandLine::StringType run_as_user =
- command_line.GetSwitchValueNative(kRunAsUser);
- CommandLine::StringType run_as_password =
- command_line.GetSwitchValueNative(kRunAsPassword);
-
- hr = ValidateUserDataDir(run_as_user.c_str());
-
- hr = InstallService(run_as_user.c_str(), run_as_password.c_str());
+ hr = InstallService(run_as_user.c_str(), run_as_password.c_str(),
+ kServiceSwitch);
if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch))
return StartService();
@@ -323,8 +323,10 @@ class CloudPrintServiceModule
if (command_line.HasSwitch(kStartSwitch))
return StartService();
- if (command_line.HasSwitch(kServiceSwitch)) {
+ if (command_line.HasSwitch(kServiceSwitch) ||
+ command_line.HasSwitch(kPrintersSwitch)) {
*is_service = true;
+ detect_printers_ = command_line.HasSwitch(kPrintersSwitch);
return S_OK;
}
@@ -339,23 +341,46 @@ class CloudPrintServiceModule
return S_FALSE;
}
- HRESULT ValidateUserDataDir(const string16& user) {
- FilePath temp_file;
- const char some_data[] = "1234";
- if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file))
- return E_FAIL;
- HRESULT hr = WriteFileAsUser(temp_file, user, some_data,
- sizeof(some_data));
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to write user data. Make sure that account \'" <<
- user << "\' has full access to \'" <<
- user_data_dir_.value() << "\'.";
+ void SelectWindowsAccount(string16* run_as_user,
+ string16* run_as_password) {
+ *run_as_user = GetCurrentUserName();
+ for (;;) {
+ std::cout << "\nPlease provide Windows account to run service.\n";
+ *run_as_user = ASCIIToWide(GetOption("Account as DOMAIN\\USERNAME",
+ WideToASCII(*run_as_user), false));
+ *run_as_password = ASCIIToWide(GetOption("Password", "", true));
+
+ FilePath printers_filename(user_data_dir_);
+ printers_filename = printers_filename.Append(kPrintersFileName);
+
+ file_util::Delete(printers_filename, false);
+ if (FAILED(InstallService(run_as_user->c_str(),
+ run_as_password->c_str(),
+ kPrintersSwitch))) {
+ continue;
+ }
+ if (FAILED(StartService())) {
+ LOG(ERROR) << "Failed to start service as " << *run_as_user << ".";
+ continue;
+ }
+ UninstallService();
+ if (!file_util::PathExists(printers_filename)) {
+ LOG(ERROR) << "Service can't create " << printers_filename.value();
+ continue;
+ }
+
+ std::string printers;
+ file_util::ReadFileToString(printers_filename, &printers);
+ std::cout << "\nPrinters available for " << run_as_user << ":\n";
+ std::cout << printers << "\n";
+ file_util::Delete(printers_filename, false);
+
+ if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?"))
+ return;
}
- file_util::Delete(temp_file, false);
- return hr;
}
- HRESULT ProcessServiceState(bool quiet) {
+ HRESULT SetupServiceState() {
FilePath file = user_data_dir_.Append(kServiceStateFileName);
for (;;) {
@@ -365,38 +390,28 @@ class CloudPrintServiceModule
bool is_valid = file_util::ReadFileToString(file, &contents) &&
service_state.FromString(contents);
- if (!quiet) {
- std::cout << "\n";
- std::cout << file.value() << ":\n";
- std::cout << contents << "\n";
- }
+ std::cout << "\nFile '" << file.value() << "' content:\n";
+ std::cout << contents << "\n";
if (!is_valid)
LOG(ERROR) << "Invalid file: " << file.value();
- if (quiet)
- return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
-
if (!contents.empty()) {
- std::cout << "Do you want to use this file [y/n]:";
- for (;;) {
- std::string input;
- std::getline(std::cin, input);
- StringToLowerASCII(&input);
- if (input == "y") {
- return S_OK;
- } else if (input == "n") {
- is_valid = false;
- break;
- }
+ if (AskUser("Do you want to use '" + WideToASCII(file.value()) + "'")) {
+ return S_OK;
+ } else {
+ is_valid = false;
}
}
while (!is_valid) {
+ std::cout << "\nPlease provide Cloud Print Settings.\n";
std::string email = GetOption("email", service_state.email(), false);
std::string password = GetOption("password", "", true);
- std::string proxy_id = GetOption("connector_id",
- service_state.proxy_id(), false);
+ std::string proxy_id = service_state.proxy_id();
+ if (proxy_id.empty())
+ proxy_id = base::GenerateGUID();
+ proxy_id = GetOption("connector_id", proxy_id, false);
is_valid = service_state.Configure(email, password, proxy_id);
if (is_valid) {
std::string new_contents = service_state.ToString();
@@ -455,12 +470,32 @@ class CloudPrintServiceModule
HRESULT StopService() {
ServiceHandle service;
- HRESULT hr = OpenService(SERVICE_STOP, &service);
+ HRESULT hr = OpenService(SERVICE_STOP | SERVICE_QUERY_STATUS, &service);
if (FAILED(hr))
return hr;
SERVICE_STATUS status = {0};
if (!::ControlService(service, SERVICE_CONTROL_STOP, &status))
return HResultFromLastError();
+ while (::QueryServiceStatus(service, &status) &&
+ status.dwCurrentState > SERVICE_STOPPED) {
+ Sleep(500);
+ }
+ return S_OK;
+ }
+
+ HRESULT DetectPrinters() {
+ FilePath printers_filename(user_data_dir_);
+ printers_filename = printers_filename.Append(kPrintersFileName);
+ std::string printers;
+ scoped_refptr<printing::PrintBackend> backend(
+ printing::PrintBackend::CreateInstance(NULL));
+ printing::PrinterList printer_list;
+ backend->EnumeratePrinters(&printer_list);
+ for (size_t i = 0; i < printer_list.size(); ++i) {
+ printers += printer_list[i].printer_name;
+ printers += "\n";
+ }
+ file_util::WriteFile(printers_filename, printers.c_str(), printers.size());
return S_OK;
}
@@ -470,12 +505,15 @@ class CloudPrintServiceModule
}
void StopConnector() {
- chrome_->Stop();
- chrome_.reset();
+ if (chrome_.get()) {
+ chrome_->Stop();
+ chrome_.reset();
+ }
}
static BOOL WINAPI ConsoleCtrlHandler(DWORD type);
+ bool detect_printers_;
FilePath user_data_dir_;
scoped_ptr<ChromeLauncher> chrome_;
};