--- /dev/null
+/*-*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file usb-access-map.cpp
+ * @author Jan Cybulski <j.cybulski@samsung.com>
+ * @author Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version 1.0
+ * @brief Implementation of classes that gathers information about
+ * applications' access rights to usb files for purpose of raw USB usage.
+ */
+
+#include <usb-access-map.h>
+#include <usb-security-daemon.h>
+#include <dpl/log/log.h>
+#include <cstring>
+#include <limits.h>
+#include <string>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+#include <sys/smack.h>
+#include <linux/usb/ch9.h>
+#include <endian.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define USB_DEVICE_MAJOR 189
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a))
+
+using namespace std;
+
+namespace USD {
+
+void USBDevicePath::initFromSysFS(const std::string &path)
+{
+ char buf[PATH_MAX];
+ char *ret_chp;
+
+ ret_chp = realpath(path.c_str(), buf);
+ if (!ret_chp)
+ throw USD_API_ERROR_FILE_NOT_EXIST;
+ m_sysPath = string(buf);
+
+ if (m_dev == 0) {
+ /* it is not dev node! */
+ ifstream dev_file(m_sysPath + "/dev");
+ string content;
+ int min, maj;
+ int ret;
+
+ dev_file >> content;
+ ret = sscanf(content.c_str(), "%d:%d", &maj, &min);
+ if (ret < 3)
+ throw USD_API_ERROR_FILE_READ_FAILED;
+
+ if (maj != USB_DEVICE_MAJOR)
+ throw USD_API_ERROR_ACCESS_DENIED;
+
+ m_dev = makedev(maj, min);
+ }
+}
+
+void USBDevicePath::initFromTopology(const std::string &path)
+{
+ string usb_path = path;
+ size_t ret;
+
+ ret = path.find_first_of('/');
+ if (ret != string::npos)
+ usb_path = path.substr(0, ret);
+
+ /*
+ * TODO: This is a good vector of attack.
+ * Revisit this function and check if it is really
+ * safe and any malformed path can lead us outside sysfs
+ * For example: path=../../../../tmp/my_fake_dir"
+ * would work without above code
+ */
+ initFromSysFS(string("/sys/bus/usb/devices/") + path);
+}
+
+void USBDevicePath::initFromDev(const std::string &path)
+{
+ struct stat dev_st;
+ char buf[PATH_MAX];
+ string spath;
+ int ret;
+
+ ret = stat(path.c_str(), &dev_st);
+ if (ret < 0)
+ throw USD_API_ERROR_FILE_READ_FAILED;
+
+ if (!S_ISCHR(dev_st.st_mode) ||
+ major(dev_st.st_dev) != USB_DEVICE_MAJOR)
+ throw USD_API_ERROR_ACCESS_DENIED;
+
+ m_dev = dev_st.st_dev;
+ ret = snprintf(buf, sizeof(buf),
+ "/sys/dev/chr/%d:%d", major(m_dev), minor(m_dev));
+ /*
+ * If this happened we have really big troubles,
+ * probably it end of the world
+ */
+ if ((unsigned)ret >= sizeof(buf))
+ throw USD_API_ERROR_BUFFER_TOO_SMALL;
+
+ initFromSysFS(buf);
+}
+
+USBDevicePath::USBDevicePath(const string &path,
+ PathType path_type)
+ : m_dev(0)
+{
+ switch (path_type) {
+ case PATH_TYPE_DEV:
+ initFromDev(path);
+ break;
+ case PATH_TYPE_TOPO:
+ initFromTopology(path);
+ break;
+ case PATH_TYPE_SYSFS:
+ initFromSysFS(path);
+ break;
+ }
+}
+
+const std::string &USBDevicePath::getSysFSPath() const
+{
+ return m_sysPath;
+}
+
+dev_t USBDevicePath::getDev() const
+{
+ return m_dev;
+}
+
+std::ostream &operator<<(std::ostream &stream,
+ const USBDevicePath &path)
+{
+
+ stream << '(' << major(path.m_dev) << ':' << minor(path.m_dev) << ", "
+ << path.m_sysPath << ')';
+
+ return stream;
+}
+
+/****** USBDeviceId ******/
+
+USBDeviceId::USBDeviceId(const string &path, USBDevicePath::PathType path_type)
+ : m_path(path, path_type)
+{
+ initDevId(m_path.getSysFSPath());
+}
+
+USBDeviceId::USBDeviceId(const USBDevicePath &path)
+ : m_path(path)
+{
+ initDevId(m_path.getSysFSPath());
+}
+
+void USBDeviceId::initDevId(const std::string &sys_path)
+{
+ int fd;
+ int ret;
+ struct usb_device_descriptor desc;
+ std::string path;
+
+ path += sys_path + "/descriptors";
+
+ fd = open(path.c_str(), O_RDONLY);
+ if (fd < 0)
+ throw USD_API_ERROR_FILE_OPEN_FAILED;
+
+ ret = read(fd, &desc, sizeof(desc));
+ close(fd);
+ if ((unsigned)ret < sizeof(desc))
+ throw USD_API_ERROR_FILE_READ_FAILED;
+
+ m_bcdUSB = le16toh(desc.bcdUSB);
+ m_bDeviceClass = desc.bDeviceClass;
+ m_bDeviceSubClass = desc.bDeviceSubClass;
+ m_bDeviceProtocol = desc.bDeviceProtocol;
+ m_idVendor = le16toh(desc.idVendor);
+ m_idProduct = le16toh(desc.idProduct);
+ m_bcdDevice = le16toh(desc.bcdDevice);
+}
+
+bool USBDeviceId::operator<(const USBDeviceId &r) const
+{
+ int i;
+
+ /*
+ * We don't test major because we know that
+ * all USB devices have the same major
+ */
+#define VALUES(field) \
+ { .our = this->field, .other = r.field, }
+
+ struct {
+ int our;
+ int other;
+ } values[] = {
+ {
+ .our = minor(m_path.getDev()),
+ .other = minor(r.m_path.getDev()),
+ },
+ VALUES(m_idVendor),
+ VALUES(m_idProduct),
+ VALUES(m_bcdDevice),
+ VALUES(m_bDeviceClass),
+ VALUES(m_bDeviceSubClass),
+ VALUES(m_bDeviceProtocol),
+ VALUES(m_bcdUSB),
+ };
+
+#undef VALUES
+
+ for (i = 0; (unsigned)i < ARRAY_SIZE(values); ++i)
+ if (values[i].our != values[i].other)
+ return values[i].our < values[i].other;
+
+ return m_path.getSysFSPath() < r.m_path.getSysFSPath();
+}
+
+bool USBDeviceId::operator==(const USBDeviceId &r) const
+{
+#define FIELD_NE(field) (this->field != r.field)
+
+ if (FIELD_NE(m_path.getDev()))
+ return false;
+
+ if (FIELD_NE(m_idVendor))
+ return false;
+
+ if (FIELD_NE(m_idProduct))
+ return false;
+
+ if (FIELD_NE(m_bcdDevice))
+ return false;
+
+ if (FIELD_NE(m_bDeviceClass))
+ return false;
+
+ if (FIELD_NE(m_bDeviceSubClass))
+ return false;
+
+ if (FIELD_NE(m_bDeviceProtocol))
+ return false;
+
+ if (FIELD_NE(m_bcdUSB))
+ return false;
+#undef FIELD_NE
+
+ return m_path.getSysFSPath() == r.m_path.getSysFSPath();
+}
+
+bool USBDeviceId::operator!=(const USBDeviceId &r) const
+{
+ return !(*this == r);
+}
+
+std::ostream &operator<<(std::ostream &stream,
+ const USBDeviceId &id)
+{
+#define NAMED_VAL(field) { .name = #field, .val = id.m_##field, }
+ struct {
+ const char *name;
+ int val;
+ } fields[] = {
+ NAMED_VAL(idVendor),
+ NAMED_VAL(idProduct),
+ NAMED_VAL(bcdDevice),
+ NAMED_VAL(bDeviceClass),
+ NAMED_VAL(bDeviceSubClass),
+ NAMED_VAL(bDeviceProtocol),
+ NAMED_VAL(bcdUSB),
+ };
+#undef NAMED_VAL
+ int i = 0;
+
+ stream << "(";
+ for (i = 0; (unsigned)i < ARRAY_SIZE(fields); ++i)
+ stream << fields[i].name << ": " << std::hex << fields[i].val << ", ";
+
+ stream << "devicePath: " << id.m_path;
+
+ stream << ")";
+
+ return stream;
+}
+} /* namespace USD */
--- /dev/null
+/*-*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file usb-access.h
+ * @author Jan Cybulski <j.cybulski@samsung.com>
+ * @author Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version 1.0
+ * @brief Header for classes that gathers information about
+ * applications' access rights to usb files for purpose of raw USB usage.
+ */
+
+#ifndef USB_ACCESS_MAP_H_
+#define USB_ACCESS_MAP_H_
+
+#include <string>
+#include <iostream>
+#include <dpl/serialization.h>
+
+namespace USD {
+
+class USBDevicePath
+{
+public:
+ enum PathType {
+ PATH_TYPE_DEV,
+ PATH_TYPE_TOPO,
+ PATH_TYPE_SYSFS,
+ };
+
+ /* Never call this constructor with SysFS path received from user! */
+ USBDevicePath(const std::string &path, PathType path_type);
+ const std::string &getSysFSPath() const;
+ dev_t getDev() const;
+
+ friend std::ostream &operator<<(std::ostream &stream,
+ const USBDevicePath &path);
+private:
+ void initFromSysFS(const std::string &path);
+ void initFromTopology(const std::string &path);
+ void initFromDev(const std::string &path);
+ std::string m_sysPath;
+ dev_t m_dev;
+};
+
+/*
+ * As for now identifier may be just values from device descriptor,
+ * but later this may be changed, so more flexible rules may be
+ * introduced.
+ */
+class USBDeviceId
+{
+public:
+ USBDeviceId(const USBDevicePath &path);
+ USBDeviceId(const std::string &path, USBDevicePath::PathType path_type);
+
+ bool operator<(const USBDeviceId &r) const;
+ bool operator==(const USBDeviceId &r) const;
+ bool operator!=(const USBDeviceId &r) const;
+
+ friend std::ostream &operator<<(std::ostream &stream,
+ const USBDeviceId &id);
+
+private:
+ void initDevId(const std::string &sys_path);
+
+ uint16_t m_bcdUSB;
+ uint8_t m_bDeviceClass;
+ uint8_t m_bDeviceSubClass;
+ uint8_t m_bDeviceProtocol;
+ uint16_t m_idVendor;
+ uint16_t m_idProduct;
+ uint16_t m_bcdDevice;
+ /*
+ * We should consider here also strings but it requires device
+ * communication, so should be discussed later.
+ * std::string m_iManufacturer;
+ * std::string m_iProduct;
+ * std::string m_iSerialNumber;
+ */
+
+ USBDevicePath m_path;
+};
+
+} /* namespace USD */
+
+#endif /* USB_ACCESS_MAP_H_ */