${SERVER2_PATH}/main/generic-socket-manager.cpp
${SERVER2_PATH}/main/socket-manager.cpp
${SERVER2_PATH}/main/server2-main.cpp
+ ${SERVER2_PATH}/service/usb-access.cpp
)
SET_SOURCE_FILES_PROPERTIES(
SET(USD_CLIENT_SOURCES
${SERVER2_PATH}/client/client-common.cpp
+ ${SERVER2_PATH}/client/usb-access-client.cpp
)
ADD_LIBRARY(${TARGET_USD_CLIENT} SHARED ${USD_CLIENT_SOURCES})
--- /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-client.cpp
+ * @author Jan Cybulski <j.cybulski@samsung.com>
+ * @author Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version 1.0
+ * @brief This file is implementation of client functions for usb access service.
+ */
+
+#include <usb-security-daemon.h>
+#include <usd-util.h>
+#include <cstring>
+#include <dpl/log/log.h>
+#include <dpl/exception.h>
+#include <message-buffer.h>
+#include <client-common.h>
+#include <protocols.h>
+#include <sys/socket.h>
+
+
+namespace {
+
+void create_msghdr(struct msghdr *hdr,
+ struct iovec *iov,
+ unsigned char *cmsgbuf,
+ const size_t cmsgbufSize,
+ int *retcode)
+ {
+ memset(hdr, 0, sizeof(*hdr));
+ memset(cmsgbuf, 0, cmsgbufSize);
+
+ iov->iov_base = retcode;
+ iov->iov_len = sizeof(*retcode);
+ hdr->msg_iov = iov;
+ hdr->msg_iovlen = 1;
+
+ if (NULL != cmsgbuf) {
+ hdr->msg_control = cmsgbuf;
+ hdr->msg_controllen = cmsgbufSize;
+ }
+}
+
+} // namespace anonymous
+
+_USD_API_
+int usd_open_usb_device(const char *devpath, int *fd)
+{
+ LogDebug("devpath: " << devpath);
+ using namespace USD;
+ return try_catch([&] {
+ MessageBuffer send;
+ struct msghdr hdr;
+ struct iovec iov;
+ unsigned char cmsgbuf[CMSG_SPACE(sizeof(int))];
+ int retcode = -1;
+ int result;
+
+ if (nullptr == devpath || nullptr == fd || !strlen(devpath)) {
+ LogError("Error input param.");
+ return USD_API_ERROR_INPUT_PARAM;
+ }
+
+ Serialization::Serialize(send,
+ static_cast<int>(USBAccessCall::USB_CALL_TYPE_OPEN));
+ Serialization::Serialize(send, std::string(devpath));
+
+ create_msghdr(&hdr, &iov, &cmsgbuf[0], sizeof(cmsgbuf), &retcode);
+
+ result = sendToServerAncData(SERVICE_SOCKET_USB_ACCESS,
+ send.Pop(), hdr);
+ if (result != USD_API_SUCCESS) {
+ *fd = -1;
+ return result;
+ }
+
+ if (hdr.msg_flags & MSG_CTRUNC) {
+ LogError("Not enough space for ancillary element array.");
+ *fd = -1;
+ return USD_API_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ for(cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
+ if((SOL_SOCKET == cmsg->cmsg_level) &&
+ (SCM_RIGHTS == cmsg->cmsg_type)) {
+ memmove(fd, CMSG_DATA(cmsg), sizeof(int));
+ }
+ }
+ return retcode;
+ });
+}
+
+_USD_API_
+int usd_setup_usb_device_access(const char *topology, const char *smack, bool allow) {
+ LogDebug(" topology: " << topology << "smack: " << smack << "allow" << allow);
+ using namespace USD;
+ return try_catch([&] {
+ MessageBuffer send;
+ struct msghdr hdr;
+ struct iovec iov;
+ int retcode = -1;
+
+ if (nullptr == topology || !strlen(topology) ||
+ nullptr == smack || !strlen(smack)) {
+ LogError("Error input param.");
+ return USD_API_ERROR_INPUT_PARAM;
+ }
+
+ Serialization::Serialize(send,
+ static_cast<int>(USBAccessCall::USB_CALL_TYPE_SETUP_POLICY));
+ Serialization::Serialize(send, std::string(smack));
+ Serialization::Serialize(send, std::string(topology));
+ Serialization::Serialize(send, allow);
+
+ create_msghdr(&hdr, &iov, NULL, 0, &retcode);
+
+ int result = sendToServerAncData(SERVICE_SOCKET_USB_ACCESS, send.Pop(), hdr);
+ if (result != USD_API_SUCCESS)
+ return result;
+
+ if (hdr.msg_flags & MSG_CTRUNC) {
+ LogError("Not enough space for ancillary element array.");
+ return USD_API_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ return retcode;
+ });
+}
namespace USD {
-extern char const * const SERVICE_SOCKET_USB_ACCESS;
+extern char const *const SERVICE_SOCKET_USB_ACCESS;
-
-
-enum class UsbAccessCall
+enum class USBAccessCall
{
USB_CALL_TYPE_OPEN,
USB_CALL_TYPE_SETUP_POLICY
return stream;
}
+
+/****** PolicySubjectId ******/
+
+PolicySubjectId::PolicySubjectId(const std::string &smk)
+ : m_smk(smk)
+{
+ /* Nothing to do here */
+}
+
+PolicySubjectId::PolicySubjectId(int socket)
+{
+ char *smk;
+ ssize_t ret;
+
+ ret = smack_new_label_from_socket(socket, &smk);
+ if (ret < 0)
+ throw USD_API_ERROR_GETTING_SOCKET_LABEL_FAILED;
+
+ m_smk = smk;
+ free(smk);
+}
+
+PolicySubjectId::PolicySubjectId(IStream &str)
+{
+ Deserialization::Deserialize(str, m_smk);
+}
+
+bool PolicySubjectId::operator<(const PolicySubjectId &r) const
+{
+ return this->m_smk < r.m_smk;
+}
+
+bool PolicySubjectId::operator==(const PolicySubjectId &r) const
+{
+ return this->m_smk == r.m_smk;
+}
+
+std::ostream& operator<<(std::ostream& stream, const PolicySubjectId& id)
+{
+ return stream << id.m_smk;
+}
+
+/****** USBAccessMapKey ******/
+
+USBAccessMapKey::USBAccessMapKey(const PolicySubjectId &subject,
+ const USBDeviceId &device)
+ : m_subject(subject), m_device(device)
+{
+ /* Nothing to do here */
+}
+
+bool USBAccessMapKey::validate() const
+{
+ /* TODO */
+ return true;
+}
+
+bool USBAccessMapKey::operator<(const USBAccessMapKey &r) const
+{
+ if (m_device != r.m_device)
+ return m_device < r.m_device;
+
+ return m_subject < r.m_subject;
+}
+
+bool USBAccessMapKey::operator==(const USBAccessMapKey &r) const
+{
+ if (m_device != r.m_device)
+ return false;
+
+ return m_subject == r.m_subject;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+ const USBAccessMapKey& key)
+{
+ stream << "(" << key.m_subject << ", " << key.m_device << ")";
+ return stream;
+}
+
} /* namespace USD */
+
USBDevicePath m_path;
};
+/**
+ * Application identifier, a subject of policy entry that is
+ * unique for a given app.
+ *
+ * As for now, this may be just smack label.
+ * If later this will be used on a multi-user system, we might add
+ * here additional field for user identifier. As for now it is not needed.
+ */
+class PolicySubjectId
+{
+public:
+ PolicySubjectId(const std::string &smk);
+ PolicySubjectId(int socket);
+ PolicySubjectId(IStream &str);
+
+ bool operator<(const PolicySubjectId &r) const;
+ bool operator==(const PolicySubjectId &r) const;
+
+ friend std::ostream& operator<<(std::ostream& stream,
+ const PolicySubjectId& id);
+
+private:
+ std::string m_smk;
+};
+
+/**
+ * This is a key for searching in a USBAccessMap structure
+ */
+class USBAccessMapKey
+{
+public:
+ USBAccessMapKey(const PolicySubjectId &subject,
+ const USBDeviceId &device);
+ bool validate(void) const;
+
+ bool operator<(const USBAccessMapKey &r) const;
+ bool operator==(const USBAccessMapKey &r) const;
+ friend std::ostream& operator<<(std::ostream& stream,
+ const USBAccessMapKey& key);
+
+private:
+ PolicySubjectId m_subject;
+ USBDeviceId m_device;
+};
+
+
+typedef std::map<USBAccessMapKey, bool> USBAccessMap;
+
} /* namespace USD */
#endif /* USB_ACCESS_MAP_H_ */
#include <socket-manager.h>
+#include <usb-access.h>
IMPLEMENT_SAFE_SINGLETON(USD::Log::LogSystem);
LogInfo("Start!");
USD::SocketManager manager;
+ REGISTER_SOCKET_SERVICE(manager, USD::USBAccessService);
manager.MainLoop();
}
--- /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.lewandowski@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.cpp
+ * @author Jan Cybulski <j.cybulski@samsung.com>
+ * @author Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version 1.0
+ * @brief Implementation of service for granting usb raw data access.
+ */
+
+#include <dpl/log/log.h>
+#include <dpl/serialization.h>
+
+#include <protocols.h>
+#include <usb-security-daemon.h>
+#include <usd-util.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <usb-access.h>
+#include <usb-access-map.h>
+
+namespace {
+// Service may open more than one socket.
+// These ID's will be assigned to sockets
+// and will be used only by service.
+// When new connection arrives, AcceptEvent
+// will be generated with proper ID to inform
+// service about input socket.
+//
+// Please note: SocketManaged does not use it and
+// does not check it in any way.
+//
+// If your service require only one socket
+// (uses only one socket labeled with smack)
+// you may ignore this ID (just pass 0)
+const int SERVICE_SOCKET_ID = 0;
+
+} // namespace anonymous
+
+
+
+namespace USD {
+
+GenericSocketService::ServiceDescriptionVector
+USBAccessService::GetServiceDescription()
+{
+ ServiceDescriptionVector description = {
+ {
+ /* service's socket path */
+ .path = SERVICE_SOCKET_USB_ACCESS,
+ /* service's socket smack label */
+ .smackLabel = "usd::api-usb-access",
+ /* service's interface id */
+ .interfaceID = SERVICE_SOCKET_ID,
+ /* service is using sendMsg */
+ .useSendMsg = true,
+ }
+ };
+
+ return description;
+}
+
+void USBAccessService::accept(const AcceptEvent &event)
+{
+ LogDebug("Accept event. "
+ << "ConnectionID.sock: " << event.connectionID.sock
+ << " ConnectionID.counter: " << event.connectionID.counter
+ << " ServiceID: " << event.interfaceID);
+}
+
+void USBAccessService::write(const WriteEvent &event)
+{
+ LogDebug("WriteEvent. "
+ << "ConnectionID: " << event.connectionID.sock
+ << " Size: " << event.size
+ << " Left: " << event.left);
+
+ if (event.left == 0)
+ m_serviceManager->Close(event.connectionID);
+}
+
+bool USBAccessService::checkAccessEntry(PolicySubjectId subjectId,
+ const USBDeviceId &devId)
+{
+ USBAccessMapKey key(subjectId, devId);
+
+ LogDebug("checkAccessEntry begin");
+ LogDebug("key: " << key);
+
+ auto it = m_accessMap.find(key);
+ if (it == m_accessMap.end()) {
+ LogDebug("There is no entry in the database. Return deny.");
+ return false;
+ }
+
+ LogDebug("There is an entry in a database. "
+ "Return value of policy: " << it->second);
+
+ return it->second;
+}
+
+static inline int openFileForClient(const char *path, int &fd)
+{
+ fd = TEMP_FAILURE_RETRY(open(path, O_RDWR));
+ if (fd < 0) {
+ LogError("Cannot open file: " << path);
+ return USD_API_ERROR_FILE_NOT_EXIST;
+ }
+
+ LogDebug("Opened file: '" << path << "' fd: " << fd);
+ return USD_API_SUCCESS;
+}
+
+bool USBAccessService::processOpen(const ConnectionID &conn,
+ MessageBuffer &buffer)
+{
+ int fd = -1;
+ int retCode = USD_API_ERROR_SERVER_ERROR;
+
+ LogDebug("Processing USB_CALL_TYPE_OPEN");
+
+ try {
+ std::string path;
+ bool accessGranted;
+ PolicySubjectId peerId(conn.sock);
+
+ Deserialization::Deserialize(buffer, path);
+
+ USBDeviceId devId(path, USBDevicePath::PATH_TYPE_DEV);
+
+ accessGranted = checkAccessEntry(peerId, devId);
+ if (accessGranted) {
+ LogDebug("Access granted for opening: "
+ << path << " which belongs to: " << devId
+ << " by: " << peerId);
+ retCode = openFileForClient(path.c_str(), fd);
+ } else {
+ retCode = USD_API_ERROR_ACCESS_DENIED;
+ }
+ } catch(int e) {
+ retCode = e;
+ }
+
+ /* Send the result */
+ SendMsgData sendMsgData(retCode, fd);
+ m_serviceManager->Write(conn, sendMsgData);
+ /* We always return true because we have proccessed this message */
+ return true;
+}
+
+bool USBAccessService::processSetupPolicy(const ConnectionID &conn,
+ MessageBuffer &buffer)
+{
+ int retCode = USD_API_ERROR_SERVER_ERROR;
+
+ LogDebug("Processing USB_CALL_TYPE_SETUP_POLICY");
+ try {
+ std::string smack, path;
+ bool policy;
+ bool valid;
+
+ Deserialization::Deserialize(buffer, smack);
+ Deserialization::Deserialize(buffer, path);
+
+ USBAccessMapKey mk(smack,
+ USBDeviceId(path, USBDevicePath::PATH_TYPE_TOPO));
+
+ Deserialization::Deserialize(buffer, policy);
+ LogDebug("policy: " << policy
+ << ", smack: " << smack << ", path: " << path);
+
+ valid = mk.validate();
+ LogDebug("Validation" << (valid ? "ok" : "failed")
+ <<" on: " << mk << ", policy: " << policy);
+ if (valid) {
+ m_accessMap[mk] = policy;
+ retCode = USD_API_SUCCESS;
+ } else {
+ retCode = USD_API_ERROR_ACCESS_DENIED;
+ }
+ } catch(int e) {
+ LogDebug("Error occured on processing: " << e);
+ retCode = e;
+ }
+
+ /* Send the result */
+ SendMsgData sendMsgData(retCode, -1);
+ m_serviceManager->Write(conn, sendMsgData);
+
+ /* We always return true because we have proccessed this message */
+ return true;
+}
+
+bool USBAccessService::processOne(const ConnectionID &conn,
+ MessageBuffer &buffer)
+{
+ LogDebug("Iteration begin");
+ bool ret = true;
+
+ if (!buffer.Ready())
+ return false;
+
+ Try {
+ USBAccessCall callType;
+ int tmp;
+
+ Deserialization::Deserialize(buffer, tmp);
+ callType = static_cast<USBAccessCall>(tmp);
+
+ switch(callType) {
+ case USBAccessCall::USB_CALL_TYPE_OPEN:
+ ret = processOpen(conn, buffer);
+ break;
+
+ case USBAccessCall::USB_CALL_TYPE_SETUP_POLICY:
+ ret = processSetupPolicy(conn, buffer);
+ break;
+
+ default:
+ LogDebug("Broken protocol. Closing socket.");
+ m_serviceManager->Close(conn);
+ ret = false;
+ }
+ } Catch (MessageBuffer::Exception::Base) {
+ LogDebug("Broken protocol. Closing socket.");
+ m_serviceManager->Close(conn);
+ ret = false;
+ }
+
+ return ret;
+}
+
+void USBAccessService::process(const ReadEvent &event)
+{
+ LogDebug("Read event for counter: " << event.connectionID.counter);
+
+ auto &buffer = m_messageBufferMap[event.connectionID.counter];
+ buffer.Push(event.rawBuffer);
+
+ /*
+ * We can get several requests in one package.
+ * Extract and process them all
+ */
+ while(processOne(event.connectionID, buffer));
+}
+
+void USBAccessService::close(const CloseEvent &event)
+{
+ LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
+ m_messageBufferMap.erase(event.connectionID.counter);
+}
+
+} // 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: Jan Cybulski <j.cybulski@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 Implementation of service for granting usb raw data access.
+ */
+
+#ifndef USD_USB_ACCESS_H_
+#define USD_USB_ACCESS_H_
+
+#include <usb-access-map.h>
+#include <service-thread.h>
+#include <generic-socket-manager.h>
+
+#include <dpl/serialization.h>
+#include <message-buffer.h>
+#include <usb-access-map.h>
+
+namespace USD {
+
+class USBAccessService :
+ public USD::GenericSocketService,
+ public USD::ServiceThread<USBAccessService>
+{
+public:
+ typedef std::map<int, MessageBuffer> MessageBufferMap;
+
+ ServiceDescriptionVector GetServiceDescription();
+
+ DECLARE_THREAD_EVENT(AcceptEvent, accept)
+ DECLARE_THREAD_EVENT(WriteEvent, write)
+ DECLARE_THREAD_EVENT(ReadEvent, process)
+ DECLARE_THREAD_EVENT(CloseEvent, close)
+
+ void accept(const AcceptEvent &event);
+ void write(const WriteEvent &event);
+ void process(const ReadEvent &event);
+ void close(const CloseEvent &event);
+
+private:
+ bool processOne(const ConnectionID &conn, MessageBuffer &buffer);
+ bool processOpen(const ConnectionID &conn, MessageBuffer &buffer);
+ bool processSetupPolicy(const ConnectionID &conn, MessageBuffer &buffer);
+ bool checkAccessEntry(PolicySubjectId subjectId, const USBDeviceId &devId);
+
+ MessageBufferMap m_messageBufferMap;
+ USBAccessMap m_accessMap;
+};
+
+} /* namespace USD */
+
+#endif /* USD_USB_ACCESS_H_ */
INSTALL(FILES
${CMAKE_SOURCE_DIR}/USD/systemd/usd.service
+ ${CMAKE_SOURCE_DIR}/USD/systemd/usd-access.socket
DESTINATION
${SYSTEMD_DIR}
)
--- /dev/null
+[Socket]
+ListenStream=/run/usd/usd-api-usb-access.socket
+SocketMode=0777
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+
+Service=usd.service
+
+
+[Install]
+WantedBy=sockets.target
[Service]
Type=notify
ExecStart=/usr/bin/usd
+Sockets=usd-access.socket
[Install]
WantedBy=multi-user.target
mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants
mkdir -p %{buildroot}%{_unitdir}/sockets.target.wants
ln -s ../usd.service %{buildroot}%{_unitdir}/multi-user.target.wants/usd.service
+ln -s ../usd-access.socket %{buildroot}%{_unitdir}/sockets.target.wants/usd-access.socket
%post -p /sbin/ldconfig
%{_libdir}/libusd-commons.so.*
%attr(-,root,root) %{_unitdir}/multi-user.target.wants/usd.service
%attr(-,root,root) %{_unitdir}/usd.service
+%attr(-,root,root) %{_unitdir}/sockets.target.wants/usd-access.socket
+%attr(-,root,root) %{_unitdir}/usd-access.socket
%{_datadir}/license/%{name}
%files libusd-client