Home | History | Annotate | Download | only in win
      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 
     21 const char SetupListener::kXpsAvailableJsonValueName[] = "xps_available";
     22 const char SetupListener::kChromePathJsonValueName[] = "chrome_path";
     23 const char SetupListener::kPrintersJsonValueName[] = "printers";
     24 const char SetupListener::kUserDataDirJsonValueName[] = "user_data_dir";
     25 const char SetupListener::kUserNameJsonValueName[] = "user_name";
     26 const wchar_t SetupListener::kSetupPipeName[] =
     27     L"\\\\.\\pipe\\CloudPrintServiceSetup";
     28 
     29 SetupListener::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 
     41 SetupListener::~SetupListener() {
     42   ipc_thread_->message_loop()->PostTask(FROM_HERE,
     43                                         base::Bind(&SetupListener::Disconnect,
     44                                                    base::Unretained(this)));
     45   ipc_thread_->Stop();
     46 }
     47 
     48 bool 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 
     84 void SetupListener::OnChannelError() {
     85   done_event_->Signal();
     86 }
     87 
     88 bool SetupListener::WaitResponce(const base::TimeDelta& delta) {
     89   return done_event_->TimedWait(delta) && succeded_;
     90 }
     91 
     92 void SetupListener::Disconnect() {
     93   channel_.reset();
     94   ipc_thread_->message_loop()->QuitWhenIdle();
     95 }
     96 
     97 void 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