12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cloud_print/service/win/setup_listener.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <atlbase.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <atlsecurity.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/guid.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/platform_thread.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/win/service_utils.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_channel.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char SetupListener::kXpsAvailableJsonValueName[] = "xps_available";
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char SetupListener::kChromePathJsonValueName[] = "chrome_path";
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char SetupListener::kPrintersJsonValueName[] = "printers";
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char SetupListener::kUserDataDirJsonValueName[] = "user_data_dir";
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char SetupListener::kUserNameJsonValueName[] = "user_name";
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t SetupListener::kSetupPipeName[] =
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    L"\\\\.\\pipe\\CloudPrintServiceSetup";
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)SetupListener::SetupListener(const base::string16& user)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : done_event_(new base::WaitableEvent(true, false)),
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ipc_thread_(new base::Thread("ipc_thread")),
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      succeded_(false),
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      is_xps_available_(false) {
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_thread_->StartWithOptions(
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_thread_->message_loop()->PostTask(
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&SetupListener::Connect, base::Unretained(this), user));
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SetupListener::~SetupListener() {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ipc_thread_->message_loop()->PostTask(FROM_HERE,
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        base::Bind(&SetupListener::Disconnect,
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   base::Unretained(this)));
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ipc_thread_->Stop();
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SetupListener::OnMessageReceived(const IPC::Message& msg) {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PickleIterator iter(msg);
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json_string;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!iter.ReadString(&json_string))
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::DictionaryValue* dictionary = NULL;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!value || !value->GetAsDictionary(&dictionary) || !dictionary) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Invalid response from service";
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::ListValue* printers = NULL;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (dictionary->GetList(kPrintersJsonValueName, &printers) && printers) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < printers->GetSize(); ++i) {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string printer;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (printers->GetString(i, &printer) && !printer.empty())
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        printers_.push_back(printer);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dictionary->GetBoolean(kXpsAvailableJsonValueName, &is_xps_available_);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->GetString(kUserNameJsonValueName, &user_name_);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 chrome_path;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->GetString(kChromePathJsonValueName, &chrome_path);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome_path_ = base::FilePath(chrome_path);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 user_data_dir;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dictionary->GetString(kUserDataDirJsonValueName, &user_data_dir);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  user_data_dir_ = base::FilePath(user_data_dir);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  succeded_ = true;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  done_event_->Signal();
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SetupListener::OnChannelError() {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  done_event_->Signal();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SetupListener::WaitResponce(const base::TimeDelta& delta) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return done_event_->TimedWait(delta) && succeded_;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SetupListener::Disconnect() {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  channel_.reset();
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ipc_thread_->message_loop()->QuitWhenIdle();
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void SetupListener::Connect(const base::string16& user) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ATL::CDacl dacl;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ATL::CSid user_sid;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!user_sid.LoadAccount(ReplaceLocalHostInName(user).c_str())) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to load Sid for" << user;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dacl.AddAllowedAce(user_sid, GENERIC_READ | GENERIC_WRITE);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ATL::CSecurityDesc desk;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  desk.SetDacl(dacl);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ATL::CSecurityAttributes attribs(desk);
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedHandle pipe(
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateNamedPipe(kSetupPipeName,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      FILE_FLAG_FIRST_PIPE_INSTANCE,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      IPC::Channel::kReadBufferSize,
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      IPC::Channel::kReadBufferSize, 5000, &attribs));
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (pipe.IsValid()) {
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    channel_ = IPC::Channel::CreateServer(IPC::ChannelHandle(pipe.Get()),
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                          this);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    channel_->Connect();
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
126