libbrillo: policy: Add GetUsbDetachableWhitelist for new USB policy

The newly added device policy setting |usb_detachable_whitelist| contains
a list of USB devices (identified by their USB VID:PID pairs) which can be
detached from the kernel drivers in order to use them in web application.
Add a GetUsbDetachableWhitelist method to retrieve this list of devices.
(as used by the permission_broker daemon)

The policy_all file was updated to include a usb_detachable_whitelist
policy with a couple of USB devices with VID:PID 0403:6001 and
413c:2105.

BUG=chrome-os-partner:50249
TEST=`FEATURES=test emerge-samus libbrillo permission_broker`

Change-Id: If4b06a85ab0b9641e615692449d434e41bd457e6
diff --git a/policy/device_policy.h b/policy/device_policy.h
index 78be238..840e7e5 100644
--- a/policy/device_policy.h
+++ b/policy/device_policy.h
@@ -26,6 +26,15 @@
 // definition from leaking into the libraries using this interface.
 class DevicePolicy {
  public:
+  // Identifiers of a USB device or device family.
+  struct UsbDeviceId {
+    // USB Vendor Identifier (aka idVendor).
+    uint16_t vendor_id;
+
+    // USB Product Identifier (aka idProduct).
+    uint16_t product_id;
+  };
+
   DevicePolicy();
   virtual ~DevicePolicy();
 
@@ -136,6 +145,11 @@
   virtual bool GetAllowKioskAppControlChromeVersion(
       bool* allow_kiosk_app_control_chrome_version) const = 0;
 
+  // Writes the value of the UsbDetachableWhitelist policy in |usb_whitelist|.
+  // Returns true on success.
+  virtual bool GetUsbDetachableWhitelist(
+      std::vector<UsbDeviceId>* usb_whitelist) const = 0;
+
  private:
   // Verifies that the policy files are owned by root and exist.
   virtual bool VerifyPolicyFiles() = 0;
diff --git a/policy/device_policy_impl.cc b/policy/device_policy_impl.cc
index f28df52..784cace 100644
--- a/policy/device_policy_impl.cc
+++ b/policy/device_policy_impl.cc
@@ -405,6 +405,23 @@
   return true;
 }
 
+bool DevicePolicyImpl::GetUsbDetachableWhitelist(
+    std::vector<UsbDeviceId>* usb_whitelist) const {
+  if (!device_policy_.has_usb_detachable_whitelist())
+    return false;
+  const enterprise_management::UsbDetachableWhitelistProto& proto =
+      device_policy_.usb_detachable_whitelist();
+  usb_whitelist->clear();
+  for (int i = 0; i < proto.id_size(); i++) {
+    const ::enterprise_management::UsbDeviceIdProto& id = proto.id(i);
+    UsbDeviceId dev_id;
+    dev_id.vendor_id = id.has_vendor_id() ? id.vendor_id() : 0;
+    dev_id.product_id = id.has_product_id() ? id.product_id() : 0;
+    usb_whitelist->push_back(dev_id);
+  }
+  return true;
+}
+
 bool DevicePolicyImpl::VerifyPolicyFiles() {
   // Both the policy and its signature have to exist.
   if (!base::PathExists(policy_path_) || !base::PathExists(keyfile_path_)) {
diff --git a/policy/device_policy_impl.h b/policy/device_policy_impl.h
index b2f2bd4..db22475 100644
--- a/policy/device_policy_impl.h
+++ b/policy/device_policy_impl.h
@@ -60,6 +60,8 @@
   virtual bool GetAuP2PEnabled(bool* au_p2p_enabled) const;
   virtual bool GetAllowKioskAppControlChromeVersion(
       bool* allow_kiosk_app_control_chrome_version) const;
+  virtual bool GetUsbDetachableWhitelist(
+      std::vector<UsbDeviceId>* usb_whitelist) const;
 
  protected:
   // Verifies that the policy files are owned by root and exist.
diff --git a/policy/mock_device_policy.h b/policy/mock_device_policy.h
index 7742b07..cabba91 100644
--- a/policy/mock_device_policy.h
+++ b/policy/mock_device_policy.h
@@ -94,6 +94,8 @@
                      bool(bool*));  // NOLINT(readability/function)
   MOCK_CONST_METHOD1(GetAllowKioskAppControlChromeVersion,
                      bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetUsbDetachableWhitelist,
+                     bool(std::vector<DevicePolicy::UsbDeviceId>*));
 
   MOCK_METHOD0(VerifyPolicyFiles, bool(void));
   MOCK_METHOD0(VerifyPolicySignature, bool(void));
diff --git a/policy/tests/libpolicy_unittest.cc b/policy/tests/libpolicy_unittest.cc
index 0fc0461..2946ee7 100644
--- a/policy/tests/libpolicy_unittest.cc
+++ b/policy/tests/libpolicy_unittest.cc
@@ -154,6 +154,14 @@
   ASSERT_TRUE(policy.GetAllowKioskAppControlChromeVersion(&bool_value));
   ASSERT_FALSE(bool_value);
 
+  std::vector<DevicePolicy::UsbDeviceId> list_device;
+  ASSERT_TRUE(policy.GetUsbDetachableWhitelist(&list_device));
+  ASSERT_EQ(2, list_device.size());
+  ASSERT_EQ(0x413c, list_device[0].vendor_id);
+  ASSERT_EQ(0x2105, list_device[0].product_id);
+  ASSERT_EQ(0x0403, list_device[1].vendor_id);
+  ASSERT_EQ(0x6001, list_device[1].product_id);
+
   // Reloading the protobuf should succeed.
   ASSERT_TRUE(provider.Reload());
 }
@@ -179,6 +187,7 @@
   std::vector<std::string> list_value;
   bool bool_value;
   std::string string_value;
+  std::vector<DevicePolicy::UsbDeviceId> list_device;
 
   ASSERT_FALSE(policy.GetPolicyRefreshRate(&int_value));
   ASSERT_FALSE(policy.GetUserWhitelist(&list_value));
@@ -200,6 +209,7 @@
   ASSERT_FALSE(policy.GetHttpDownloadsEnabled(&bool_value));
   ASSERT_FALSE(policy.GetAuP2PEnabled(&bool_value));
   ASSERT_FALSE(policy.GetAllowKioskAppControlChromeVersion(&bool_value));
+  ASSERT_FALSE(policy.GetUsbDetachableWhitelist(&list_device));
 }
 
 // Verify that the library will correctly recognize and signal missing files.
diff --git a/policy/tests/whitelist/policy_all b/policy/tests/whitelist/policy_all
index a2359bd..333f240 100644
--- a/policy/tests/whitelist/policy_all
+++ b/policy/tests/whitelist/policy_all
Binary files differ