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