1 // Copyright 2014 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 "extensions/common/permissions/usb_device_permission.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/check.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/features/behavior_feature.h"
18 #include "extensions/common/features/feature.h"
19 #include "extensions/common/features/feature_provider.h"
20 #include "extensions/common/permissions/permissions_info.h"
21 #include "extensions/strings/grit/extensions_strings.h"
22 #include "services/device/public/cpp/usb/usb_ids.h"
23 #include "ui/base/l10n/l10n_util.h"
24
25 namespace extensions {
26
27 namespace {
28
29 const int kHidInterfaceClass = 3;
30
IsInterfaceClassPermissionAlowed(const Extension * extension)31 bool IsInterfaceClassPermissionAlowed(const Extension* extension) {
32 const Feature* feature = FeatureProvider::GetBehaviorFeature(
33 behavior_feature::kAllowUsbDevicesPermissionInterfaceClass);
34 if (!feature)
35 return false;
36 if (!extension)
37 return false;
38 return feature->IsAvailableToExtension(extension).is_available();
39 }
40
41 } // namespace
42
43 // static
44 std::unique_ptr<UsbDevicePermission::CheckParam>
ForUsbDevice(const Extension * extension,const device::mojom::UsbDeviceInfo & device_info)45 UsbDevicePermission::CheckParam::ForUsbDevice(
46 const Extension* extension,
47 const device::mojom::UsbDeviceInfo& device_info) {
48 return CheckParam::ForUsbDeviceAndInterface(
49 extension, device_info,
50 UsbDevicePermissionData::SPECIAL_VALUE_UNSPECIFIED);
51 }
52
53 // static
54 std::unique_ptr<UsbDevicePermission::CheckParam>
ForDeviceWithAnyInterfaceClass(const Extension * extension,uint16_t vendor_id,uint16_t product_id,int interface_id)55 UsbDevicePermission::CheckParam::ForDeviceWithAnyInterfaceClass(
56 const Extension* extension,
57 uint16_t vendor_id,
58 uint16_t product_id,
59 int interface_id) {
60 return std::make_unique<CheckParam>(extension, vendor_id, product_id,
61 std::unique_ptr<std::set<int>>(),
62 interface_id);
63 }
64
65 // static
66 std::unique_ptr<UsbDevicePermission::CheckParam>
ForUsbDeviceAndInterface(const Extension * extension,const device::mojom::UsbDeviceInfo & device_info,int interface_id)67 UsbDevicePermission::CheckParam::ForUsbDeviceAndInterface(
68 const Extension* extension,
69 const device::mojom::UsbDeviceInfo& device_info,
70 int interface_id) {
71 std::unique_ptr<std::set<int>> interface_classes(new std::set<int>());
72 // If device class is set, match interface class against it as well. This is
73 // to enable filtering devices by device-only class (for example, hubs), which
74 // might or might not have an interface with class set to device class value.
75 if (device_info.class_code)
76 interface_classes->insert(device_info.class_code);
77
78 for (const auto& configuration : device_info.configurations) {
79 for (const auto& interface : configuration->interfaces) {
80 for (const auto& alternate : interface->alternates)
81 interface_classes->insert(alternate->class_code);
82 }
83 }
84
85 return std::make_unique<CheckParam>(
86 extension, device_info.vendor_id, device_info.product_id,
87 std::move(interface_classes), interface_id);
88 }
89
90 // static
91 std::unique_ptr<UsbDevicePermission::CheckParam>
ForHidDevice(const Extension * extension,uint16_t vendor_id,uint16_t product_id)92 UsbDevicePermission::CheckParam::ForHidDevice(const Extension* extension,
93 uint16_t vendor_id,
94 uint16_t product_id) {
95 std::unique_ptr<std::set<int>> interface_classes(new std::set<int>());
96 interface_classes->insert(kHidInterfaceClass);
97 return std::make_unique<UsbDevicePermission::CheckParam>(
98 extension, vendor_id, product_id, std::move(interface_classes),
99 UsbDevicePermissionData::SPECIAL_VALUE_UNSPECIFIED);
100 }
101
CheckParam(const Extension * extension,uint16_t vendor_id,uint16_t product_id,std::unique_ptr<std::set<int>> interface_classes,int interface_id)102 UsbDevicePermission::CheckParam::CheckParam(
103 const Extension* extension,
104 uint16_t vendor_id,
105 uint16_t product_id,
106 std::unique_ptr<std::set<int>> interface_classes,
107 int interface_id)
108 : vendor_id(vendor_id),
109 product_id(product_id),
110 interface_classes(std::move(interface_classes)),
111 interface_id(interface_id),
112 interface_class_allowed(IsInterfaceClassPermissionAlowed(extension)) {}
113
~CheckParam()114 UsbDevicePermission::CheckParam::~CheckParam() {}
115
UsbDevicePermission(const APIPermissionInfo * info)116 UsbDevicePermission::UsbDevicePermission(const APIPermissionInfo* info)
117 : SetDisjunctionPermission<UsbDevicePermissionData, UsbDevicePermission>(
118 info) {}
119
~UsbDevicePermission()120 UsbDevicePermission::~UsbDevicePermission() {}
121
FromValue(const base::Value * value,std::string * error,std::vector<std::string> * unhandled_permissions)122 bool UsbDevicePermission::FromValue(
123 const base::Value* value,
124 std::string* error,
125 std::vector<std::string>* unhandled_permissions) {
126 bool parsed_ok =
127 SetDisjunctionPermission<UsbDevicePermissionData, UsbDevicePermission>::
128 FromValue(value, error, unhandled_permissions);
129 if (parsed_ok && data_set_.empty()) {
130 if (error)
131 *error = "NULL or empty permission list";
132 return false;
133 }
134 return parsed_ok;
135 }
136
GetPermissions() const137 PermissionIDSet UsbDevicePermission::GetPermissions() const {
138 PermissionIDSet ids;
139
140 std::set<uint16_t> unknown_product_vendors;
141 bool found_unknown_vendor = false;
142
143 for (const UsbDevicePermissionData& data : data_set_) {
144 // Interface class permissions should be only available in kiosk sessions,
145 // don't include those in installation warning for now.
146 if (data.interface_class() != UsbDevicePermissionData::SPECIAL_VALUE_ANY)
147 continue;
148 const char* vendor = device::UsbIds::GetVendorName(data.vendor_id());
149 if (vendor) {
150 const char* product =
151 device::UsbIds::GetProductName(data.vendor_id(), data.product_id());
152 if (product) {
153 base::string16 product_name_and_vendor = l10n_util::GetStringFUTF16(
154 IDS_EXTENSION_USB_DEVICE_PRODUCT_NAME_AND_VENDOR,
155 base::UTF8ToUTF16(product), base::UTF8ToUTF16(vendor));
156 ids.insert(APIPermission::kUsbDevice, product_name_and_vendor);
157 } else {
158 unknown_product_vendors.insert(data.vendor_id());
159 }
160 } else {
161 found_unknown_vendor = true;
162 }
163 }
164
165 for (uint16_t vendor_id : unknown_product_vendors) {
166 const char* vendor = device::UsbIds::GetVendorName(vendor_id);
167 DCHECK(vendor);
168 ids.insert(APIPermission::kUsbDeviceUnknownProduct,
169 base::UTF8ToUTF16(vendor));
170 }
171
172 if (found_unknown_vendor)
173 ids.insert(APIPermission::kUsbDeviceUnknownVendor);
174
175 return ids;
176 }
177
178 } // namespace extensions
179