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