${SECURITY_SERVER_PATH}/server/security-server-password.c
${SECURITY_SERVER_PATH}/util/security-server-util-common.c
${SECURITY_SERVER_PATH}/util/smack-check.c
+ ${SERVER2_PATH}/main/generic-socket-manager.cpp
${SERVER2_PATH}/main/socket-manager.cpp
${SERVER2_PATH}/main/server2-main.cpp
${SERVER2_PATH}/service/data-share.cpp
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Bumjin Im <bj.im@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 generic-socket-manager.cpp
+ * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version 1.0
+ * @brief Implementation of GenericSocketService and GenericSocketManager.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <generic-socket-manager.h>
+
+namespace SecurityServer {
+
+class SendMsgData::Internal {
+public:
+ Internal(int resultCode, int fileDesc)
+ : m_resultCode(resultCode)
+ , m_fileDesc(fileDesc)
+ {
+ memset(&m_hdr, 0, sizeof(msghdr));
+ memset(m_cmsgbuf, 0, CMSG_SPACE(sizeof(int)));
+
+ m_iov.iov_base = &m_resultCode;
+ m_iov.iov_len = sizeof(m_resultCode);
+
+ m_hdr.msg_iov = &m_iov;
+ m_hdr.msg_iovlen = 1;
+ m_hdr.msg_control = m_cmsgbuf;
+ m_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
+
+ m_cmsg = CMSG_FIRSTHDR(&m_hdr);
+ m_cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ m_cmsg->cmsg_level = SOL_SOCKET;
+ m_cmsg->cmsg_type = SCM_RIGHTS;
+
+ memmove(CMSG_DATA(m_cmsg), &m_fileDesc, sizeof(int));
+ }
+
+ msghdr* data() { return &m_hdr; }
+
+private:
+ msghdr m_hdr;
+ iovec m_iov;
+ cmsghdr *m_cmsg;
+ unsigned char m_cmsgbuf[CMSG_SPACE(sizeof(int))];
+ int m_resultCode;
+ int m_fileDesc;
+};
+
+SendMsgData::SendMsgData()
+ : m_resultCode(0)
+ , m_fileDesc(-1)
+ , m_flags(0)
+ , m_pimpl(NULL)
+{}
+
+SendMsgData::SendMsgData(int resultCode, int fileDesc, int flags)
+ : m_resultCode(resultCode)
+ , m_fileDesc(fileDesc)
+ , m_flags(flags)
+ , m_pimpl(NULL)
+{}
+
+SendMsgData::SendMsgData(const SendMsgData &second)
+ : m_resultCode(second.m_resultCode)
+ , m_fileDesc(second.m_fileDesc)
+ , m_flags(second.m_flags)
+ , m_pimpl(NULL)
+{}
+
+SendMsgData::~SendMsgData() {
+ delete m_pimpl;
+}
+
+SendMsgData& SendMsgData::operator=(const SendMsgData &second) {
+ m_resultCode = second.m_resultCode;
+ m_fileDesc = second.m_fileDesc;
+ m_flags = second.m_flags;
+ delete m_pimpl;
+ m_pimpl = NULL;
+ return *this;
+}
+
+msghdr* SendMsgData::getMsghdr() {
+ if (!m_pimpl)
+ m_pimpl = new Internal(m_resultCode, m_fileDesc);
+ return m_pimpl->data();
+}
+
+int SendMsgData::flags() {
+ return m_flags;
+}
+
+} // namespace SecurityServer
+
#include <generic-event.h>
+extern "C" {
+struct msghdr;
+} // extern "C"
+
namespace SecurityServer {
typedef int InterfaceID;
typedef std::string SmackLabel;
typedef std::string ServiceHandlerPath;
struct ServiceDescription {
+ ServiceDescription(const char *path,
+ const char *smackLabel,
+ InterfaceID interfaceID = 0,
+ bool useSendMsg = false)
+ : smackLabel(smackLabel)
+ , interfaceID(interfaceID)
+ , serviceHandlerPath(path)
+ , useSendMsg(useSendMsg)
+ {}
+
SmackLabel smackLabel; // Smack label for socket
InterfaceID interfaceID; // All data from serviceHandlerPath will be marked with this interfaceHandler
ServiceHandlerPath serviceHandlerPath; // Path to file
+ bool useSendMsg;
};
typedef std::vector<ServiceDescription> ServiceDescriptionVector;
GenericSocketManager *m_serviceManager;
};
+class SendMsgData {
+public:
+ class Internal;
+
+ SendMsgData();
+ SendMsgData(int resultCode, int fileDesc, int flags = 0);
+ SendMsgData(const SendMsgData &second);
+ SendMsgData& operator=(const SendMsgData &second);
+ virtual ~SendMsgData();
+
+ msghdr* getMsghdr();
+ int flags();
+private:
+ int m_resultCode;
+ int m_fileDesc;
+ int m_flags;
+ Internal *m_pimpl;
+};
+
struct GenericSocketManager {
virtual void MainLoop() = 0;
virtual void RegisterSocketService(GenericSocketService *ptr) = 0;
virtual void Close(ConnectionID connectionID) = 0;
virtual void Write(ConnectionID connectionID, const RawBuffer &rawBuffer) = 0;
+ virtual void Write(ConnectionID connectionID, const SendMsgData &sendMsgData) = 0;
virtual ~GenericSocketManager(){}
};
auto &desc = CreateDefaultReadSocketDescription(client, true);
desc.interfaceID = m_socketDescriptionVector[sock].interfaceID;
desc.service = m_socketDescriptionVector[sock].service;
+ desc.useSendMsg = m_socketDescriptionVector[sock].useSendMsg;
GenericSocketService::AcceptEvent event;
event.connectionID.sock = client;
}
}
-void SocketManager::ReadyForWrite(int sock) {
+void SocketManager::ReadyForSendMsg(int sock) {
+ auto &desc = m_socketDescriptionVector[sock];
+
+ if (desc.sendMsgDataQueue.empty()) {
+ FD_CLR(sock, &m_writeSet);
+ return;
+ }
+
+ auto data = desc.sendMsgDataQueue.front();
+ ssize_t result = sendmsg(sock, data.getMsghdr(), data.flags());
+
+ if (result == -1) {
+ int err = errno;
+ switch(err) {
+ case EAGAIN:
+ case EINTR:
+ break;
+ case EPIPE:
+ default:
+ LogDebug("Error during send: " << strerror(err));
+ CloseSocket(sock);
+ break;
+ }
+ return;
+ } else {
+ desc.sendMsgDataQueue.pop();
+ }
+
+ if (desc.sendMsgDataQueue.empty()) {
+ FD_CLR(sock, &m_writeSet);
+ }
+
+ desc.timeout = time(NULL) + SOCKET_TIMEOUT;
+
+ GenericSocketService::WriteEvent event;
+ event.connectionID.sock = sock;
+ event.connectionID.counter = desc.counter;
+ event.size = result;
+ event.left = desc.sendMsgDataQueue.size();
+
+ desc.service->Event(event);
+}
+
+void SocketManager::ReadyForWriteBuffer(int sock) {
auto &desc = m_socketDescriptionVector[sock];
size_t size = desc.rawBuffer.size();
ssize_t result = write(sock, &desc.rawBuffer[0], size);
break;
case EPIPE:
default:
- int i = errno;
- LogDebug("Error during write: " << strerror(i));
+ LogDebug("Error during write: " << strerror(err));
CloseSocket(sock);
break;
}
desc.service->Event(event);
}
+void SocketManager::ReadyForWrite(int sock) {
+ m_socketDescriptionVector[sock].useSendMsg ?
+ ReadyForSendMsg(sock) : ReadyForWriteBuffer(sock);
+}
+
void SocketManager::MainLoop() {
// remove evironment values passed by systemd
// uncomment it after removing old security-server code
description.isListen = true;
description.interfaceID = desc.interfaceID;
+ description.useSendMsg = desc.useSendMsg;
description.service = service;
LogDebug("Listen on socket: " << sockfd <<
NotifyMe();
}
+void SocketManager::Write(ConnectionID connectionID, const SendMsgData &sendMsgData) {
+ WriteData data;
+ data.connectionID = connectionID;
+ data.sendMsgData = sendMsgData;
+ {
+ std::unique_lock<std::mutex> ulock(m_eventQueueMutex);
+ m_writeDataQueue.push(data);
+ }
+ NotifyMe();
+}
+
void SocketManager::NotifyMe() {
TEMP_FAILURE_RETRY(write(m_notifyMe[1], "You have message ;-)", 1));
}
void SocketManager::ProcessQueue() {
WriteBuffer buffer;
+ WriteData data;
{
std::unique_lock<std::mutex> ulock(m_eventQueueMutex);
while (!m_writeBufferQueue.empty()) {
buffer = m_writeBufferQueue.front();
m_writeBufferQueue.pop();
- if (!m_socketDescriptionVector[buffer.connectionID.sock].isOpen) {
+
+ auto &desc = m_socketDescriptionVector[buffer.connectionID.sock];
+
+ if (!desc.isOpen) {
LogDebug("Received packet for write but connection is closed. Packet ignored!");
continue;
}
- if (m_socketDescriptionVector[buffer.connectionID.sock].counter !=
- buffer.connectionID.counter)
+
+ if (desc.counter != buffer.connectionID.counter)
{
LogDebug("Received packet for write but counter is broken. Packet ignored!");
continue;
}
+
+ if (desc.useSendMsg) {
+ LogError("Some service tried to push rawdata to socket that usees sendmsg!");
+ continue;
+ }
+
std::copy(
buffer.rawBuffer.begin(),
buffer.rawBuffer.end(),
- std::back_inserter(
- m_socketDescriptionVector[buffer.connectionID.sock].rawBuffer));
+ std::back_inserter(desc.rawBuffer));
FD_SET(buffer.connectionID.sock, &m_writeSet);
}
+
+ while(!m_writeDataQueue.empty()) {
+ data = m_writeDataQueue.front();
+ m_writeDataQueue.pop();
+
+ auto &desc = m_socketDescriptionVector[data.connectionID.sock];
+
+ if (!desc.isOpen) {
+ LogDebug("Received packet for sendmsg but connection is closed. Packet ignored!");
+ continue;
+ }
+
+ if (desc.counter != data.connectionID.counter)
+ {
+ LogDebug("Received packet for write but counter is broken. Packet ignored!");
+ continue;
+ }
+
+ if (!desc.useSendMsg) {
+ LogError("Some service tries to push SendMsgData to socket that uses write!");
+ continue;
+ }
+
+ desc.sendMsgDataQueue.push(data.sendMsgData);
+
+ FD_SET(data.connectionID.sock, &m_writeSet);
+ }
}
while (1) {
desc.service = NULL;
desc.interfaceID = -1;
desc.rawBuffer.clear();
+ while(!desc.sendMsgDataQueue.empty())
+ desc.sendMsgDataQueue.pop();
if (service)
service->Event(event);
#ifndef _SECURITY_SERVER_SOCKET_MANAGER_
#define _SECURITY_SERVER_SOCKET_MANAGER_
-#include <tuple>
#include <vector>
#include <queue>
#include <string>
virtual void RegisterSocketService(GenericSocketService *service);
virtual void Close(ConnectionID connectionID);
virtual void Write(ConnectionID connectionID, const RawBuffer &rawBuffer);
+ virtual void Write(ConnectionID connectionID, const SendMsgData &sendMsgData);
protected:
void CreateDomainSocket(
void ReadyForRead(int sock);
void ReadyForWrite(int sock);
+ void ReadyForWriteBuffer(int sock);
+ void ReadyForSendMsg(int sock);
void ReadyForAccept(int sock);
void ProcessQueue(void);
void NotifyMe(void);
bool isListen;
bool isOpen;
bool isTimeout;
+ bool useSendMsg;
InterfaceID interfaceID;
GenericSocketService *service;
time_t timeout;
RawBuffer rawBuffer;
+ std::queue<SendMsgData> sendMsgDataQueue;
int counter;
SocketDescription()
: isListen(false)
, isOpen(false)
, isTimeout(false)
+ , useSendMsg(false)
, interfaceID(-1)
, service(NULL)
{}
RawBuffer rawBuffer;
};
+ struct WriteData {
+ ConnectionID connectionID;
+ SendMsgData sendMsgData;
+ };
+
struct Timeout {
time_t time;
int sock;
bool m_working;
std::mutex m_eventQueueMutex;
std::queue<WriteBuffer> m_writeBufferQueue;
+ std::queue<WriteData> m_writeDataQueue;
std::queue<ConnectionID> m_closeQueue;
int m_notifyMe[2];
int m_counter;
namespace SecurityServer {
GenericSocketService::ServiceDescriptionVector AppPermissionsService::GetServiceDescription() {
- ServiceDescription sd = {
- "security-server::api-app-permissions",
- 0,
- SERVICE_SOCKET_APP_PERMISSIONS
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_APP_PERMISSIONS, "security-server::api-app-permissions" }};
}
void AppPermissionsService::accept(const AcceptEvent &event) {
namespace SecurityServer {
GenericSocketService::ServiceDescriptionVector CookieService::GetServiceDescription() {
- ServiceDescription sd1 = {
- "security-server::api-cookie-get",
- INTERFACE_GET,
- SERVICE_SOCKET_COOKIE_GET
+ return ServiceDescriptionVector {
+ {SERVICE_SOCKET_COOKIE_GET, "security-server::api-cookie-get", INTERFACE_GET },
+ {SERVICE_SOCKET_COOKIE_CHECK, "security-server::api-cookie-check", INTERFACE_CHECK},
+ {SERVICE_SOCKET_COOKIE_CHECK_TMP, "security-server::api-cookie-check", INTERFACE_CHECK_TMP}
};
- ServiceDescription sd2 = {
- "security-server::api-cookie-check",
- INTERFACE_CHECK,
- SERVICE_SOCKET_COOKIE_CHECK
- };
- ServiceDescription sd3 = {
- "security-server::api-cookie-check",
- INTERFACE_CHECK_TMP,
- SERVICE_SOCKET_COOKIE_CHECK_TMP
- };
- ServiceDescriptionVector v;
- v.push_back(sd1);
- v.push_back(sd2);
- v.push_back(sd3);
- return v;
-}
+ }
void CookieService::accept(const AcceptEvent &event) {
LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock
#include <security-server-util.h>
#include <smack-check.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 SecurityServer {
GenericSocketService::ServiceDescriptionVector SharedMemoryService::GetServiceDescription() {
- ServiceDescription sd = {
- "security-server::api-data-share",
- SERVICE_SOCKET_ID,
- SERVICE_SOCKET_SHARED_MEMORY
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_SHARED_MEMORY, "security-server::api-data-share"}};
}
void SharedMemoryService::accept(const AcceptEvent &event) {
#include <protocols.h>
#include <echo.h>
-namespace {
-// Service may open more than one socket.
-// This ID's will be assigned to sockets.
-// This ID's 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 socet labeled with smack)
-// you may ignore this ID (just pass 0)
-const int SERVICE_SOCKET_ID = 0;
-} // namespace anonymous
-
namespace SecurityServer {
GenericSocketService::ServiceDescriptionVector EchoService::GetServiceDescription() {
- ServiceDescription sd = {
- "security-server::api-echo",
- SERVICE_SOCKET_ID,
- SERVICE_SOCKET_ECHO
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_ECHO, "security-server::api-echo"}};
}
void EchoService::accept(const AcceptEvent &event) {
#include <security-server-util.h>
#include <smack-check.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 SecurityServer {
GenericSocketService::ServiceDescriptionVector ExecPathService::GetServiceDescription() {
- ServiceDescription sd = {
- "security-server",
- SERVICE_SOCKET_ID,
- SERVICE_SOCKET_EXEC_PATH
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_EXEC_PATH, "security-server" }};
}
void ExecPathService::accept(const AcceptEvent &event) {
namespace SecurityServer {
GenericSocketService::ServiceDescriptionVector GetGidService::GetServiceDescription() {
- ServiceDescription sd = {
- "*",
- 0,
- SERVICE_SOCKET_GET_GID
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_GET_GID, "*"}};
}
void GetGidService::accept(const AcceptEvent &event) {
namespace SecurityServer {
GetObjectNameService::ServiceDescriptionVector GetObjectNameService::GetServiceDescription() {
- ServiceDescription sd = {
- "*",
- 0,
- SERVICE_SOCKET_GET_OBJECT_NAME
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_GET_OBJECT_NAME, "*"}};
}
void GetObjectNameService::accept(const AcceptEvent &event) {
#include <privilege-control.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 SecurityServer {
GenericSocketService::ServiceDescriptionVector PrivilegeByPidService::GetServiceDescription() {
- ServiceDescription sd = {
- "*",
- SERVICE_SOCKET_ID,
- SERVICE_SOCKET_PRIVILEGE_BY_PID
- };
- ServiceDescriptionVector v;
- v.push_back(sd);
- return v;
+ return ServiceDescriptionVector
+ {{SERVICE_SOCKET_PRIVILEGE_BY_PID, "*" }};
}
void PrivilegeByPidService::accept(const AcceptEvent &event) {