X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fremoting%2Fhost%2Fsetup%2Fme2me_native_messaging_host.cc;h=a2a2707890659ade02813a34c44bcfdd35389829;hb=ff3e2503a20db9193d323c1d19c38c68004dec4a;hp=fabc8b0fcb1ba3ab6975e18257ffe4b8c27a5634;hpb=7338fba38ba696536d1cc9d389afd716a6ab2fe6;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/remoting/host/setup/me2me_native_messaging_host.cc b/src/remoting/host/setup/me2me_native_messaging_host.cc index fabc8b0..a2a2707 100644 --- a/src/remoting/host/setup/me2me_native_messaging_host.cc +++ b/src/remoting/host/setup/me2me_native_messaging_host.cc @@ -3,27 +3,43 @@ // found in the LICENSE file. #include "remoting/host/setup/me2me_native_messaging_host.h" - #include #include "base/basictypes.h" #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" +#include "base/command_line.h" #include "base/logging.h" #include "base/strings/stringize_macros.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/threading/thread.h" #include "base/values.h" #include "google_apis/gaia/gaia_oauth_client.h" #include "google_apis/google_api_keys.h" +#include "ipc/ipc_channel.h" #include "net/base/net_util.h" #include "remoting/base/rsa_key_pair.h" #include "remoting/host/pin_hash.h" #include "remoting/host/setup/oauth_client.h" #include "remoting/protocol/pairing_registry.h" +#if defined(OS_WIN) +#include +#include "base/win/win_util.h" +#include "remoting/host/win/security_descriptor.h" +#endif // defined(OS_WIN) + namespace { +#if defined(OS_WIN) +// Windows will use default buffer size when 0 is passed to CreateNamedPipeW(). +const DWORD kBufferSize = 0; +const int kTimeOutMilliseconds = 2000; +const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome_remote_desktop."; +#endif // defined(OS_WIN) + // redirect_uri to use when authenticating service accounts (service account // codes are obtained "out-of-band", i.e., not through an OAuth redirect). const char* kServiceAccountRedirectUri = "oob"; @@ -37,10 +53,10 @@ const char* kSupportedFeatures[] = { // Helper to extract the "config" part of a message as a DictionaryValue. // Returns NULL on failure, and logs an error message. scoped_ptr ConfigDictionaryFromMessage( - const base::DictionaryValue& message) { + scoped_ptr message) { scoped_ptr result; const base::DictionaryValue* config_dict; - if (message.GetDictionary("config", &config_dict)) { + if (message->GetDictionary("config", &config_dict)) { result.reset(config_dict->DeepCopy()); } else { LOG(ERROR) << "'config' dictionary not found"; @@ -53,11 +69,13 @@ scoped_ptr ConfigDictionaryFromMessage( namespace remoting { Me2MeNativeMessagingHost::Me2MeNativeMessagingHost( + bool needs_elevation, scoped_ptr channel, scoped_refptr daemon_controller, scoped_refptr pairing_registry, scoped_ptr oauth_client) - : channel_(channel.Pass()), + : needs_elevation_(needs_elevation), + channel_(channel.Pass()), daemon_controller_(daemon_controller), pairing_registry_(pairing_registry), oauth_client_(oauth_client.Pass()), @@ -73,12 +91,14 @@ void Me2MeNativeMessagingHost::Start( const base::Closure& quit_closure) { DCHECK(thread_checker_.CalledOnValidThread()); + quit_closure_ = quit_closure; + channel_->Start( - base::Bind(&Me2MeNativeMessagingHost::ProcessMessage, weak_ptr_), - quit_closure); + base::Bind(&Me2MeNativeMessagingHost::ProcessRequest, weak_ptr_), + base::Bind(&Me2MeNativeMessagingHost::Stop, weak_ptr_)); } -void Me2MeNativeMessagingHost::ProcessMessage( +void Me2MeNativeMessagingHost::ProcessRequest( scoped_ptr message) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -100,35 +120,35 @@ void Me2MeNativeMessagingHost::ProcessMessage( response->SetString("type", type + "Response"); if (type == "hello") { - ProcessHello(*message, response.Pass()); + ProcessHello(message.Pass(), response.Pass()); } else if (type == "clearPairedClients") { - ProcessClearPairedClients(*message, response.Pass()); + ProcessClearPairedClients(message.Pass(), response.Pass()); } else if (type == "deletePairedClient") { - ProcessDeletePairedClient(*message, response.Pass()); + ProcessDeletePairedClient(message.Pass(), response.Pass()); } else if (type == "getHostName") { - ProcessGetHostName(*message, response.Pass()); + ProcessGetHostName(message.Pass(), response.Pass()); } else if (type == "getPinHash") { - ProcessGetPinHash(*message, response.Pass()); + ProcessGetPinHash(message.Pass(), response.Pass()); } else if (type == "generateKeyPair") { - ProcessGenerateKeyPair(*message, response.Pass()); + ProcessGenerateKeyPair(message.Pass(), response.Pass()); } else if (type == "updateDaemonConfig") { - ProcessUpdateDaemonConfig(*message, response.Pass()); + ProcessUpdateDaemonConfig(message.Pass(), response.Pass()); } else if (type == "getDaemonConfig") { - ProcessGetDaemonConfig(*message, response.Pass()); + ProcessGetDaemonConfig(message.Pass(), response.Pass()); } else if (type == "getPairedClients") { - ProcessGetPairedClients(*message, response.Pass()); + ProcessGetPairedClients(message.Pass(), response.Pass()); } else if (type == "getUsageStatsConsent") { - ProcessGetUsageStatsConsent(*message, response.Pass()); + ProcessGetUsageStatsConsent(message.Pass(), response.Pass()); } else if (type == "startDaemon") { - ProcessStartDaemon(*message, response.Pass()); + ProcessStartDaemon(message.Pass(), response.Pass()); } else if (type == "stopDaemon") { - ProcessStopDaemon(*message, response.Pass()); + ProcessStopDaemon(message.Pass(), response.Pass()); } else if (type == "getDaemonState") { - ProcessGetDaemonState(*message, response.Pass()); + ProcessGetDaemonState(message.Pass(), response.Pass()); } else if (type == "getHostClientId") { - ProcessGetHostClientId(*message, response.Pass()); + ProcessGetHostClientId(message.Pass(), response.Pass()); } else if (type == "getCredentialsFromAuthCode") { - ProcessGetCredentialsFromAuthCode(*message, response.Pass()); + ProcessGetCredentialsFromAuthCode(message.Pass(), response.Pass()); } else { LOG(ERROR) << "Unsupported request type: " << type; OnError(); @@ -136,7 +156,7 @@ void Me2MeNativeMessagingHost::ProcessMessage( } void Me2MeNativeMessagingHost::ProcessHello( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -149,10 +169,16 @@ void Me2MeNativeMessagingHost::ProcessHello( } void Me2MeNativeMessagingHost::ProcessClearPairedClients( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); + if (needs_elevation_) { + if (!DelegateToElevatedHost(message.Pass())) + SendBooleanResult(response.Pass(), false); + return; + } + if (pairing_registry_) { pairing_registry_->ClearAllPairings( base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_, @@ -163,12 +189,19 @@ void Me2MeNativeMessagingHost::ProcessClearPairedClients( } void Me2MeNativeMessagingHost::ProcessDeletePairedClient( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); + if (needs_elevation_) { + if (!DelegateToElevatedHost(message.Pass())) + SendBooleanResult(response.Pass(), false); + return; + } + std::string client_id; - if (!message.GetString(protocol::PairingRegistry::kClientIdKey, &client_id)) { + if (!message->GetString(protocol::PairingRegistry::kClientIdKey, + &client_id)) { LOG(ERROR) << "'" << protocol::PairingRegistry::kClientIdKey << "' string not found."; OnError(); @@ -185,7 +218,7 @@ void Me2MeNativeMessagingHost::ProcessDeletePairedClient( } void Me2MeNativeMessagingHost::ProcessGetHostName( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -194,18 +227,18 @@ void Me2MeNativeMessagingHost::ProcessGetHostName( } void Me2MeNativeMessagingHost::ProcessGetPinHash( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); std::string host_id; - if (!message.GetString("hostId", &host_id)) { + if (!message->GetString("hostId", &host_id)) { LOG(ERROR) << "'hostId' not found: " << message; OnError(); return; } std::string pin; - if (!message.GetString("pin", &pin)) { + if (!message->GetString("pin", &pin)) { LOG(ERROR) << "'pin' not found: " << message; OnError(); return; @@ -215,7 +248,7 @@ void Me2MeNativeMessagingHost::ProcessGetPinHash( } void Me2MeNativeMessagingHost::ProcessGenerateKeyPair( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -226,12 +259,12 @@ void Me2MeNativeMessagingHost::ProcessGenerateKeyPair( } void Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); scoped_ptr config_dict = - ConfigDictionaryFromMessage(message); + ConfigDictionaryFromMessage(message.Pass()); if (!config_dict) { OnError(); return; @@ -244,7 +277,7 @@ void Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig( } void Me2MeNativeMessagingHost::ProcessGetDaemonConfig( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -254,7 +287,7 @@ void Me2MeNativeMessagingHost::ProcessGetDaemonConfig( } void Me2MeNativeMessagingHost::ProcessGetPairedClients( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -269,7 +302,7 @@ void Me2MeNativeMessagingHost::ProcessGetPairedClients( } void Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -279,19 +312,19 @@ void Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent( } void Me2MeNativeMessagingHost::ProcessStartDaemon( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); bool consent; - if (!message.GetBoolean("consent", &consent)) { + if (!message->GetBoolean("consent", &consent)) { LOG(ERROR) << "'consent' not found."; OnError(); return; } scoped_ptr config_dict = - ConfigDictionaryFromMessage(message); + ConfigDictionaryFromMessage(message.Pass()); if (!config_dict) { OnError(); return; @@ -304,7 +337,7 @@ void Me2MeNativeMessagingHost::ProcessStartDaemon( } void Me2MeNativeMessagingHost::ProcessStopDaemon( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -314,7 +347,7 @@ void Me2MeNativeMessagingHost::ProcessStopDaemon( } void Me2MeNativeMessagingHost::ProcessGetDaemonState( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -349,7 +382,7 @@ void Me2MeNativeMessagingHost::ProcessGetDaemonState( } void Me2MeNativeMessagingHost::ProcessGetHostClientId( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -359,12 +392,12 @@ void Me2MeNativeMessagingHost::ProcessGetHostClientId( } void Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode( - const base::DictionaryValue& message, + scoped_ptr message, scoped_ptr response) { DCHECK(thread_checker_.CalledOnValidThread()); std::string auth_code; - if (!message.GetString("authorizationCode", &auth_code)) { + if (!message->GetString("authorizationCode", &auth_code)) { LOG(ERROR) << "'authorizationCode' string not found."; OnError(); return; @@ -461,4 +494,192 @@ void Me2MeNativeMessagingHost::OnError() { channel_->SendMessage(scoped_ptr()); } +void Me2MeNativeMessagingHost::Stop() { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!quit_closure_.is_null()) + base::ResetAndReturn(&quit_closure_).Run(); +} + +#if defined(OS_WIN) + +bool Me2MeNativeMessagingHost::DelegateToElevatedHost( + scoped_ptr message) { + DCHECK(thread_checker_.CalledOnValidThread()); + + EnsureElevatedHostCreated(); + + // elevated_channel_ will be null if user rejects the UAC request. + if (elevated_channel_) + elevated_channel_->SendMessage(message.Pass()); + + return elevated_channel_ != NULL; +} + +void Me2MeNativeMessagingHost::EnsureElevatedHostCreated() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(needs_elevation_); + + if (elevated_channel_) + return; + + // presubmit: allow wstring + std::wstring user_sid; + if (!base::win::GetUserSidString(&user_sid)) { + LOG(ERROR) << "Failed to query the current user SID."; + OnError(); + return; + } + + // Create a security descriptor that gives full access to the caller and + // denies access by anyone else. + std::string security_descriptor = base::StringPrintf( + "O:%1$sG:%1$sD:(A;;GA;;;%1$s)", WideToASCII(user_sid).c_str()); + + ScopedSd sd = ConvertSddlToSd(security_descriptor); + if (!sd) { + LOG_GETLASTERROR(ERROR) << "Failed to create a security descriptor for the" + << "Chromoting Me2Me native messaging host."; + OnError(); + return; + } + + SECURITY_ATTRIBUTES security_attributes = {0}; + security_attributes.nLength = sizeof(security_attributes); + security_attributes.lpSecurityDescriptor = sd.get(); + security_attributes.bInheritHandle = FALSE; + + // Generate a unique name for the input channel. + std::string input_pipe_name(kChromePipeNamePrefix); + input_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID()); + + base::win::ScopedHandle delegate_write_handle(::CreateNamedPipe( + base::ASCIIToUTF16(input_pipe_name).c_str(), + PIPE_ACCESS_OUTBOUND, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS, + 1, + kBufferSize, + kBufferSize, + kTimeOutMilliseconds, + &security_attributes)); + + if (!delegate_write_handle.IsValid()) { + LOG_GETLASTERROR(ERROR) << + "Failed to create named pipe '" << input_pipe_name << "'"; + OnError(); + return; + } + + // Generate a unique name for the input channel. + std::string output_pipe_name(kChromePipeNamePrefix); + output_pipe_name.append(IPC::Channel::GenerateUniqueRandomChannelID()); + + base::win::ScopedHandle delegate_read_handle(::CreateNamedPipe( + base::ASCIIToUTF16(output_pipe_name).c_str(), + PIPE_ACCESS_INBOUND, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS, + 1, + kBufferSize, + kBufferSize, + kTimeOutMilliseconds, + &security_attributes)); + + if (!delegate_read_handle.IsValid()) { + LOG_GETLASTERROR(ERROR) << + "Failed to create named pipe '" << output_pipe_name << "'"; + OnError(); + return; + } + + const CommandLine* current_command_line = CommandLine::ForCurrentProcess(); + const CommandLine::SwitchMap& switches = current_command_line->GetSwitches(); + CommandLine::StringVector args = current_command_line->GetArgs(); + + // Create the child process command line by copying switches from the current + // command line. + CommandLine command_line(CommandLine::NO_PROGRAM); + command_line.AppendSwitch(kElevatingSwitchName); + command_line.AppendSwitchASCII(kInputSwitchName, input_pipe_name); + command_line.AppendSwitchASCII(kOutputSwitchName, output_pipe_name); + + DCHECK(!current_command_line->HasSwitch(kElevatingSwitchName)); + for (CommandLine::SwitchMap::const_iterator i = switches.begin(); + i != switches.end(); ++i) { + command_line.AppendSwitchNative(i->first, i->second); + } + for (CommandLine::StringVector::const_iterator i = args.begin(); + i != args.end(); ++i) { + command_line.AppendArgNative(*i); + } + + // Get the name of the binary to launch. + base::FilePath binary = current_command_line->GetProgram(); + CommandLine::StringType parameters = command_line.GetCommandLineString(); + + // Launch the child process requesting elevation. + SHELLEXECUTEINFO info; + memset(&info, 0, sizeof(info)); + info.cbSize = sizeof(info); + info.lpVerb = L"runas"; + info.lpFile = binary.value().c_str(); + info.lpParameters = parameters.c_str(); + info.nShow = SW_SHOWNORMAL; + + if (!ShellExecuteEx(&info)) { + DWORD error = ::GetLastError(); + LOG_GETLASTERROR(ERROR) << "Unable to launch '" << binary.value() << "'"; + if (error != ERROR_CANCELLED) { + OnError(); + } + return; + } + + if (!::ConnectNamedPipe(delegate_write_handle.Get(), NULL)) { + DWORD error = ::GetLastError(); + if (error != ERROR_PIPE_CONNECTED) { + LOG_GETLASTERROR(ERROR) << "Unable to connect '" + << input_pipe_name << "'"; + OnError(); + return; + } + } + + if (!::ConnectNamedPipe(delegate_read_handle.Get(), NULL)) { + DWORD error = ::GetLastError(); + if (error != ERROR_PIPE_CONNECTED) { + LOG_GETLASTERROR(ERROR) << "Unable to connect '" + << output_pipe_name << "'"; + OnError(); + return; + } + } + + // Set up the native messaging channel to talk to the elevated host. + // Note that input for the elevate channel is output forthe elevated host. + elevated_channel_.reset(new NativeMessagingChannel( + delegate_read_handle.Take(), delegate_write_handle.Take())); + + elevated_channel_->Start( + base::Bind(&Me2MeNativeMessagingHost::ProcessDelegateResponse, weak_ptr_), + base::Bind(&Me2MeNativeMessagingHost::Stop, weak_ptr_)); +} + +void Me2MeNativeMessagingHost::ProcessDelegateResponse( + scoped_ptr message) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Simply pass along the response from the elevated host to the client. + channel_->SendMessage(message.Pass()); +} + +#else // defined(OS_WIN) + +bool Me2MeNativeMessagingHost::DelegateToElevatedHost( + scoped_ptr message) { + NOTREACHED(); + return false; +} + +#endif // !defined(OS_WIN) + } // namespace remoting