1 // Copyright 2019 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 "chromeos/dbus/usb/usbguard_client.h"
6 
7 #include <map>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "base/observer_list.h"
13 #include "chromeos/dbus/usb/fake_usbguard_client.h"
14 #include "chromeos/dbus/usb/usbguard_observer.h"
15 #include "dbus/bus.h"
16 #include "dbus/message.h"
17 #include "dbus/object_proxy.h"
18 #include "third_party/cros_system_api/dbus/usbguard/dbus-constants.h"
19 
20 namespace chromeos {
21 
22 namespace {
23 UsbguardClient* g_instance = nullptr;
24 }  // namespace
25 
26 class UsbguardClientImpl : public UsbguardClient {
27  public:
28   UsbguardClientImpl() = default;
29   ~UsbguardClientImpl() override = default;
30 
31   // UsbguardClient:
AddObserver(UsbguardObserver * observer)32   void AddObserver(UsbguardObserver* observer) override {
33     observers_.AddObserver(observer);
34   }
35 
36   // UsbguardClient:
RemoveObserver(UsbguardObserver * observer)37   void RemoveObserver(UsbguardObserver* observer) override {
38     observers_.RemoveObserver(observer);
39   }
40 
41   // UsbguardClient:
HasObserver(const UsbguardObserver * observer) const42   bool HasObserver(const UsbguardObserver* observer) const override {
43     return observers_.HasObserver(observer);
44   }
45 
Init(dbus::Bus * bus)46   void Init(dbus::Bus* bus) {
47     bus_ = bus;
48 
49     usbguard_proxy_ = bus_->GetObjectProxy(
50         usbguard::kUsbguardServiceName,
51         dbus::ObjectPath(usbguard::kUsbguardDevicesInterfacePath));
52 
53     usbguard_proxy_->ConnectToSignal(
54         usbguard::kUsbguardDevicesInterface,
55         usbguard::kDevicePolicyChangedSignalName,
56         base::BindRepeating(&UsbguardClientImpl::DevicePolicyChanged,
57                             weak_ptr_factory_.GetWeakPtr()),
58         base::BindOnce(&UsbguardClientImpl::OnSignalConnected,
59                        weak_ptr_factory_.GetWeakPtr()));
60   }
61 
62  private:
63   // Dispatches the DevicePolicyChanged signal with signature: uuusua{ss}
DevicePolicyChanged(dbus::Signal * signal)64   void DevicePolicyChanged(dbus::Signal* signal) {
65     dbus::MessageReader signal_reader(signal);
66     dbus::MessageReader array_reader(nullptr);
67 
68     uint32_t id;
69     uint32_t target_old;
70     uint32_t target_new;
71     std::string device_rule;
72     uint32_t rule_id;
73     if (!signal_reader.PopUint32(&id) ||
74         !signal_reader.PopUint32(&target_old) ||
75         !signal_reader.PopUint32(&target_new) ||
76         !signal_reader.PopString(&device_rule) ||
77         !signal_reader.PopUint32(&rule_id) ||
78         !signal_reader.PopArray(&array_reader)) {
79       LOG(ERROR) << "Error reading signal from usbguard: "
80                  << signal->ToString();
81       return;
82     }
83 
84     std::map<std::string, std::string> attributes;
85     while (array_reader.HasMoreData()) {
86       dbus::MessageReader dict_entry(nullptr);
87       std::string key;
88       std::string value;
89       if (!array_reader.PopDictEntry(&dict_entry) ||
90           !dict_entry.PopString(&key) || !dict_entry.PopString(&value)) {
91         LOG(ERROR) << "Error reading array from signal from usbguard: "
92                    << signal->ToString();
93         return;
94       }
95       attributes[key] = value;
96     }
97 
98     for (auto& observer : observers_) {
99       observer.DevicePolicyChanged(
100           id, static_cast<UsbguardObserver::Target>(target_old),
101           static_cast<UsbguardObserver::Target>(target_new), device_rule,
102           rule_id, attributes);
103     }
104   }
105 
106   // Called when the biometrics signal is initially connected.
OnSignalConnected(const std::string & interface_name,const std::string & signal_name,bool success)107   void OnSignalConnected(const std::string& interface_name,
108                          const std::string& signal_name,
109                          bool success) {
110     LOG_IF(ERROR, !success)
111         << "Failed to connect to usbguard signal: " << signal_name;
112   }
113 
114   dbus::Bus* bus_ = nullptr;
115   dbus::ObjectProxy* usbguard_proxy_ = nullptr;
116   base::ObserverList<UsbguardObserver> observers_;
117 
118   // Note: This should remain the last member so it'll be destroyed and
119   // invalidate its weak pointers before any other members are destroyed.
120   base::WeakPtrFactory<UsbguardClientImpl> weak_ptr_factory_{this};
121 
122   DISALLOW_COPY_AND_ASSIGN(UsbguardClientImpl);
123 };
124 
UsbguardClient()125 UsbguardClient::UsbguardClient() {
126   DCHECK(!g_instance);
127   g_instance = this;
128 }
129 
~UsbguardClient()130 UsbguardClient::~UsbguardClient() {
131   DCHECK_EQ(this, g_instance);
132   g_instance = nullptr;
133 }
134 
135 // static
Initialize(dbus::Bus * bus)136 void UsbguardClient::Initialize(dbus::Bus* bus) {
137   DCHECK(bus);
138   (new UsbguardClientImpl())->Init(bus);
139 }
140 
141 // static
InitializeFake()142 void UsbguardClient::InitializeFake() {
143   new FakeUsbguardClient();
144 }
145 
146 // static
Shutdown()147 void UsbguardClient::Shutdown() {
148   DCHECK(g_instance);
149   delete g_instance;
150 }
151 
152 // static
Get()153 UsbguardClient* UsbguardClient::Get() {
154   return g_instance;
155 }
156 
157 }  // namespace chromeos
158