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 3// found in the LICENSE file. 4 5#include "cloud_print/service/win/setup_listener.h" 6 7#include <atlbase.h> 8#include <atlsecurity.h> 9 10#include "base/bind.h" 11#include "base/guid.h" 12#include "base/json/json_reader.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/synchronization/waitable_event.h" 15#include "base/threading/platform_thread.h" 16#include "base/threading/thread.h" 17#include "base/values.h" 18#include "cloud_print/service/win/service_utils.h" 19#include "ipc/ipc_channel.h" 20 21const char SetupListener::kXpsAvailableJsonValueName[] = "xps_available"; 22const char SetupListener::kChromePathJsonValueName[] = "chrome_path"; 23const char SetupListener::kPrintersJsonValueName[] = "printers"; 24const char SetupListener::kUserDataDirJsonValueName[] = "user_data_dir"; 25const char SetupListener::kUserNameJsonValueName[] = "user_name"; 26const wchar_t SetupListener::kSetupPipeName[] = 27 L"\\\\.\\pipe\\CloudPrintServiceSetup"; 28 29SetupListener::SetupListener(const base::string16& user) 30 : done_event_(new base::WaitableEvent(true, false)), 31 ipc_thread_(new base::Thread("ipc_thread")), 32 succeded_(false), 33 is_xps_available_(false) { 34 ipc_thread_->StartWithOptions( 35 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); 36 ipc_thread_->message_loop()->PostTask( 37 FROM_HERE, 38 base::Bind(&SetupListener::Connect, base::Unretained(this), user)); 39} 40 41SetupListener::~SetupListener() { 42 ipc_thread_->message_loop()->PostTask(FROM_HERE, 43 base::Bind(&SetupListener::Disconnect, 44 base::Unretained(this))); 45 ipc_thread_->Stop(); 46} 47 48bool SetupListener::OnMessageReceived(const IPC::Message& msg) { 49 PickleIterator iter(msg); 50 std::string json_string; 51 if (!iter.ReadString(&json_string)) 52 return false; 53 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); 54 const base::DictionaryValue* dictionary = NULL; 55 if (!value || !value->GetAsDictionary(&dictionary) || !dictionary) { 56 LOG(ERROR) << "Invalid response from service"; 57 return false; 58 } 59 60 const base::ListValue* printers = NULL; 61 if (dictionary->GetList(kPrintersJsonValueName, &printers) && printers) { 62 for (size_t i = 0; i < printers->GetSize(); ++i) { 63 std::string printer; 64 if (printers->GetString(i, &printer) && !printer.empty()) 65 printers_.push_back(printer); 66 } 67 } 68 dictionary->GetBoolean(kXpsAvailableJsonValueName, &is_xps_available_); 69 dictionary->GetString(kUserNameJsonValueName, &user_name_); 70 71 base::string16 chrome_path; 72 dictionary->GetString(kChromePathJsonValueName, &chrome_path); 73 chrome_path_ = base::FilePath(chrome_path); 74 75 base::string16 user_data_dir; 76 dictionary->GetString(kUserDataDirJsonValueName, &user_data_dir); 77 user_data_dir_ = base::FilePath(user_data_dir); 78 79 succeded_ = true; 80 done_event_->Signal(); 81 return true; 82} 83 84void SetupListener::OnChannelError() { 85 done_event_->Signal(); 86} 87 88bool SetupListener::WaitResponce(const base::TimeDelta& delta) { 89 return done_event_->TimedWait(delta) && succeded_; 90} 91 92void SetupListener::Disconnect() { 93 channel_.reset(); 94 ipc_thread_->message_loop()->QuitWhenIdle(); 95} 96 97void SetupListener::Connect(const base::string16& user) { 98 ATL::CDacl dacl; 99 100 ATL::CSid user_sid; 101 if (!user_sid.LoadAccount(ReplaceLocalHostInName(user).c_str())) { 102 LOG(ERROR) << "Unable to load Sid for" << user; 103 } else { 104 dacl.AddAllowedAce(user_sid, GENERIC_READ | GENERIC_WRITE); 105 } 106 107 ATL::CSecurityDesc desk; 108 desk.SetDacl(dacl); 109 110 ATL::CSecurityAttributes attribs(desk); 111 112 base::win::ScopedHandle pipe( 113 CreateNamedPipe(kSetupPipeName, 114 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | 115 FILE_FLAG_FIRST_PIPE_INSTANCE, 116 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 117 IPC::Channel::kReadBufferSize, 118 IPC::Channel::kReadBufferSize, 5000, &attribs)); 119 if (pipe.IsValid()) { 120 channel_ = IPC::Channel::CreateServer(IPC::ChannelHandle(pipe), 121 this); 122 channel_->Connect(); 123 } 124} 125 126