BuildRequires: pkgconfig(libxml-2.0)
BuildRequires: pkgconfig(capi-system-info)
BuildRequires: pkgconfig(security-manager)
+BuildRequires: pkgconfig(cynara-client-async)
+BuildRequires: pkgconfig(cynara-creds-socket)
BuildRequires: boost-devel
Requires: libkey-manager-common = %{version}-%{release}
%{?systemd_requires}
vconf
libxml-2.0
security-manager
+ cynara-client-async
+ cynara-creds-socket
)
FIND_PACKAGE(Threads REQUIRED)
ENDIF (MOCKUP_SM MATCHES "ON")
SET(KEY_MANAGER_SOURCES
+ ${KEY_MANAGER_PATH}/main/cynara.cpp
${KEY_MANAGER_PATH}/main/generic-socket-manager.cpp
${KEY_MANAGER_PATH}/main/socket-manager.cpp
${KEY_MANAGER_PATH}/main/key-manager-main.cpp
/*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Contact: Bumjin Im <bj.im@samsung.com>
*
InterfaceID interfaceID;
MessageBuffer buffer;
Credentials credentials;
+ bool checkInProgress;
};
typedef std::map<int, ConnectionInfo> ConnectionInfoMap;
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 cynara.cpp
+ * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version 1.0
+ * @brief Support for cynara.
+ */
+#include <string>
+#include <map>
+
+#include <dpl/log/log.h>
+#include <cynara.h>
+
+#include <cynara-client-async.h>
+#include <cynara-creds-socket.h>
+
+namespace CKM {
+
+Cynara::Cynara(GenericSocketManager *socketManager)
+ : m_socketManager(socketManager)
+ , m_cynara(nullptr)
+{
+ if (CYNARA_API_SUCCESS != cynara_async_initialize(&m_cynara, NULL, ChangeStatusCallback, this))
+ {
+ LogError("Cynara initialization failed.");
+ throw std::runtime_error("Cynara initialization failed.");
+ }
+}
+
+void Cynara::Request(
+ const std::string &user,
+ const std::string &client,
+ const std::string &session,
+ const std::string &privilege,
+ StatusCallback callback)
+{
+ int ret = cynara_async_check_cache(
+ m_cynara,
+ client.c_str(),
+ session.c_str(),
+ user.c_str(),
+ privilege.c_str());
+
+ switch(ret) {
+ default:
+ case CYNARA_API_ACCESS_DENIED:
+ callback(false);
+ break;
+ case CYNARA_API_ACCESS_ALLOWED:
+ callback(true);
+ break;
+ case CYNARA_API_CACHE_MISS:
+ SendRequest(
+ user,
+ client,
+ session,
+ privilege,
+ std::move(callback));
+ }
+}
+
+void Cynara::ProcessSocket() {
+ if (CYNARA_API_SUCCESS != cynara_async_process(m_cynara)) {
+ LogError("Function: cynara_async_process failed.");
+ }
+}
+
+Cynara::~Cynara(){
+ cynara_async_finish(m_cynara);
+}
+
+void Cynara::ChangeStatus(int oldFd, int newFd, cynara_async_status status) {
+ m_socketManager->CynaraSocket(oldFd, newFd, status == CYNARA_STATUS_FOR_RW);
+}
+
+void Cynara::ProcessResponse(
+ cynara_check_id checkId,
+ cynara_async_call_cause cause,
+ int response)
+{
+ auto it = m_callbackMap.find(checkId);
+
+ if (it == m_callbackMap.end())
+ return;
+
+ if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
+ it->second(true);
+ else
+ it->second(false);
+
+ m_callbackMap.erase(it);
+}
+
+void Cynara::SendRequest(
+ const std::string &user,
+ const std::string &client,
+ const std::string &session,
+ const std::string &privilege,
+ StatusCallback callback)
+{
+ cynara_check_id checkId = 0;
+ int ret = cynara_async_create_request(
+ m_cynara,
+ client.c_str(),
+ session.c_str(),
+ user.c_str(),
+ privilege.c_str(),
+ &checkId,
+ ProcessResponseCallback,
+ this);
+
+ if (ret != CYNARA_API_SUCCESS)
+ return callback(false);
+
+ m_callbackMap.emplace(checkId, std::move(callback));
+}
+
+void Cynara::ChangeStatusCallback(
+ int oldFd,
+ int newFd,
+ cynara_async_status status,
+ void *ptr)
+{
+ static_cast<Cynara*>(ptr)->ChangeStatus(oldFd, newFd, status);
+}
+
+void Cynara::ProcessResponseCallback(
+ cynara_check_id checkId,
+ cynara_async_call_cause cause,
+ int response,
+ void *ptr)
+{
+ static_cast<Cynara*>(ptr)->ProcessResponse(checkId, cause, response);
+}
+
+bool Cynara::GetUserFromSocket(int socket, std::string &user) {
+ char *ptr;
+ if (CYNARA_API_SUCCESS != cynara_creds_socket_get_user(socket, USER_METHOD_DEFAULT, &ptr))
+ return false;
+ user = ptr;
+ free(ptr);
+ return true;
+}
+
+bool Cynara::GetClientFromSocket(int socket, std::string &client) {
+ char *ptr;
+ if (CYNARA_API_SUCCESS!=cynara_creds_socket_get_client(socket, CLIENT_METHOD_DEFAULT, &ptr))
+ return false;
+ client = ptr;
+ free(ptr);
+ return true;
+}
+
+} // namespace CKM
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 cynara.h
+ * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version 1.0
+ * @brief Support for cynara.
+ */
+#pragma once
+
+#include <string>
+#include <map>
+#include <functional>
+
+#include <noncopyable.h>
+#include <generic-socket-manager.h>
+#include <cynara-client-async.h>
+
+namespace CKM {
+
+class Cynara {
+public:
+ typedef std::function<void(bool)> StatusCallback;
+ explicit Cynara(GenericSocketManager *socketManager);
+
+ NONCOPYABLE(Cynara)
+
+ void Request(
+ const std::string &user,
+ const std::string &client,
+ const std::string &session,
+ const std::string &privilege,
+ StatusCallback callback);
+
+ void ProcessSocket();
+
+ virtual ~Cynara();
+
+ static bool GetUserFromSocket(int socket, std::string &user);
+ static bool GetClientFromSocket(int socket, std::string &client);
+
+protected:
+ void ChangeStatus(int oldFd, int newFd, cynara_async_status status);
+ void ProcessResponse(cynara_check_id checkId, cynara_async_call_cause cause, int response);
+ void SendRequest(
+ const std::string &user,
+ const std::string &client,
+ const std::string &session,
+ const std::string &privilege,
+ StatusCallback callback);
+ static void ChangeStatusCallback(
+ int oldFd,
+ int newFd,
+ cynara_async_status status,
+ void *ptr);
+
+ static void ProcessResponseCallback(
+ cynara_check_id checkId,
+ cynara_async_call_cause cause,
+ int response,
+ void *ptr);
+
+ GenericSocketManager *m_socketManager;
+ cynara_async *m_cynara;
+ std::map<cynara_check_id, StatusCallback> m_callbackMap;
+};
+
+} // namespace CKM
/*
- * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Contact: Bumjin Im <bj.im@samsung.com>
*
typedef std::string ServiceHandlerPath;
struct ServiceDescription {
ServiceDescription(const char *path,
- const char *smackLabel,
+ const char *privilege,
InterfaceID interfaceID = 0,
bool useSendMsg = false)
- : smackLabel(smackLabel)
+ : privilege(privilege)
, interfaceID(interfaceID)
, serviceHandlerPath(path)
, useSendMsg(useSendMsg)
{}
- Label smackLabel; // Smack label for socket
+ std::string privilege; // privilege for socket
InterfaceID interfaceID; // All data from serviceHandlerPath will be marked with this interfaceHandler
ServiceHandlerPath serviceHandlerPath; // Path to file
bool useSendMsg;
ConnectionID connectionID;
};
+ struct SecurityEvent : public GenericEvent {
+ ConnectionID connectionID;
+ bool allowed;
+ };
+
virtual void SetSocketManager(GenericSocketManager *manager) {
m_serviceManager = manager;
}
virtual void Event(const WriteEvent &event) = 0;
virtual void Event(const ReadEvent &event) = 0;
virtual void Event(const CloseEvent &event) = 0;
+ virtual void Event(const SecurityEvent &event) = 0;
virtual void Start() = 0;
virtual void Stop() = 0;
struct GenericSocketManager {
virtual void MainLoop() = 0;
virtual void RegisterSocketService(GenericSocketService *ptr) = 0;
+ virtual void CynaraSocket(int oldFd, int newFd, bool isRW) = 0;
virtual void Close(ConnectionID connectionID) = 0;
virtual void Write(ConnectionID connectionID, const RawBuffer &rawBuffer) = 0;
+ virtual void SecurityCheck(ConnectionID connectionID) = 0;
virtual ~GenericSocketManager(){}
};
#include <socket-manager.h>
#include <socket-2-id.h>
+#include <cynara.h>
+
namespace {
const time_t SOCKET_TIMEOUT = 1000;
void Event(const WriteEvent &) {}
void Event(const ReadEvent &) {}
void Event(const CloseEvent &) {}
+ void Event(const SecurityEvent &) {}
};
struct SignalService : public GenericSocketService {
void Event(const AcceptEvent &) {} // not supported
void Event(const WriteEvent &) {} // not supported
void Event(const CloseEvent &) {} // not supported
+ void Event(const SecurityEvent &) {} // not supported
void Event(const ReadEvent &event) {
LogDebug("Get signal information");
m_socketDescriptionVector.resize(sock+20);
auto &desc = m_socketDescriptionVector[sock];
- desc.isListen = false;
- desc.isOpen = true;
+ desc.setListen(false);
+ desc.setOpen(true);
+ desc.setCynara(false);
desc.interfaceID = 0;
desc.service = NULL;
desc.counter = ++m_counter;
if (timeout) {
desc.timeout = time(NULL) + SOCKET_TIMEOUT;
- if (false == desc.isTimeout) {
- Timeout tm;
- tm.time = desc.timeout;
- tm.sock = sock;
- m_timeoutQueue.push(tm);
- }
+ Timeout tm;
+ tm.time = desc.timeout;
+ tm.sock = sock;
+ m_timeoutQueue.push(tm);
}
- desc.isTimeout = timeout;
+ desc.setTimeout(timeout);
FD_SET(sock, &m_readSet);
m_maxDesc = sock > m_maxDesc ? sock : m_maxDesc;
desc2.service = signalService;
LogInfo("SignalService mounted on " << filefd << " descriptor");
}
+
+ // We cannot create Cynara earlier because descriptors are not initialized!
+ m_cynara.reset(new Cynara(this));
}
SocketManager::~SocketManager() {
+ m_cynara.reset(nullptr);
std::set<GenericSocketService*> serviceMap;
// Find all services. Set is used to remove duplicates.
// In this implementation, services are not able to react in any way.
for (size_t i=0; i < m_socketDescriptionVector.size(); ++i)
- if (m_socketDescriptionVector[i].isOpen)
+ if (m_socketDescriptionVector[i].isOpen())
serviceMap.insert(m_socketDescriptionVector[i].service);
// Time to destroy all services.
for (auto service : serviceMap) {
LogDebug("delete " << (void*)(service));
- service->Stop();
+ if (service)
+ service->Stop();
delete service;
}
for (size_t i = 0; i < m_socketDescriptionVector.size(); ++i)
- if (m_socketDescriptionVector[i].isOpen)
+ if (m_socketDescriptionVector[i].isOpen())
close(i);
// All socket except one were closed. Now pipe input must be closed.
struct sockaddr_un clientAddr;
unsigned int clientLen = sizeof(clientAddr);
int client = accept4(sock, (struct sockaddr*) &clientAddr, &clientLen, SOCK_NONBLOCK);
-// LogInfo("Accept on sock: " << sock << " Socket opended: " << client);
if (-1 == client) {
int err = errno;
LogDebug("Error in accept: " << GetErrnoString(err));
return;
}
+ std::string smack;
+ std::string user;
Credentials peerCred;
- if (0 > getCredentialsFromSocket(client, peerCred)) {
- LogDebug("Error in getCredentialsFromSocket. Socket closed.");
+
+ if (0 > getCredentialsFromSocket(client, peerCred)
+ || !Cynara::GetUserFromSocket(client, user)
+ || !Cynara::GetClientFromSocket(client, smack))
+ {
+ LogDebug("Error in getting credentials from socket.");
TEMP_FAILURE_RETRY(close(client));
return;
}
auto &desc = CreateDefaultReadSocketDescription(client, true);
desc.interfaceID = m_socketDescriptionVector[sock].interfaceID;
desc.service = m_socketDescriptionVector[sock].service;
+ desc.cynaraPrivilege = m_socketDescriptionVector[sock].cynaraPrivilege;
+ desc.cynaraUser = std::move(user);
+ desc.cynaraClient = std::move(smack);
GenericSocketService::AcceptEvent event;
event.connectionID.sock = client;
desc.service->Event(event);
}
+void SocketManager::SecurityStatus(int sock, int counter, bool allowed) {
+ auto &desc = m_socketDescriptionVector[sock];
+ if (!desc.isOpen()) {
+ LogDebug("Client from socket " << sock <<
+ " closed connection before cynara answer was received.");
+ return;
+ }
+
+ if (desc.counter != counter) {
+ LogDebug("Client from socket " << sock <<
+ " closed connection before cynara answer was received.");
+ return;
+ }
+
+ GenericSocketService::SecurityEvent event;
+ event.connectionID.sock = sock;
+ event.connectionID.counter = counter;
+ event.allowed = allowed;
+ desc.service->Event(event);
+}
+
void SocketManager::ReadyForRead(int sock) {
- if (m_socketDescriptionVector[sock].isListen) {
+ if (m_socketDescriptionVector[sock].isListen()) {
ReadyForAccept(sock);
return;
}
+ if (m_socketDescriptionVector[sock].isCynara()) {
+ m_cynara->ProcessSocket();
+ return;
+ }
+
GenericSocketService::ReadEvent event;
event.connectionID.sock = sock;
event.connectionID.counter = m_socketDescriptionVector[sock].counter;
}
}
-void SocketManager::ReadyForWriteBuffer(int sock) {
+void SocketManager::ReadyForWrite(int sock) {
+ if (m_socketDescriptionVector[sock].isCynara()) {
+ m_cynara->ProcessSocket();
+ return;
+ }
+
auto &desc = m_socketDescriptionVector[sock];
size_t size = desc.rawBuffer.size();
ssize_t result = write(sock, &desc.rawBuffer[0], size);
desc.service->Event(event);
}
-void SocketManager::ReadyForWrite(int sock) {
- ReadyForWriteBuffer(sock);
-}
-
void SocketManager::MainLoop() {
// remove evironment values passed by systemd
sd_listen_fds(1);
auto &desc = m_socketDescriptionVector[pqTimeout.sock];
- if (!desc.isTimeout || !desc.isOpen) {
+ if (!desc.isTimeout() || !desc.isOpen()) {
// Connection was closed. Timeout is useless...
- desc.isTimeout = false;
+ desc.setTimeout(false);
continue;
}
// timeout from m_timeoutQueue matches with socket.timeout
// and connection is open. Time to close it!
// Putting new timeout in queue here is pointless.
- desc.isTimeout = false;
+ desc.setTimeout(false);
CloseSocket(pqTimeout.sock);
// All done. Now we should process next select ;-)
}
if (smack_check()) {
- LogInfo("Set up smack label: " << desc.smackLabel);
+ LogInfo("Set up smack label: " << desc.privilege);
- if (0 != smack_fsetlabel(sockfd, desc.smackLabel.c_str(), SMACK_LABEL_IPIN)) {
- LogError("Error in smack_fsetlabel");
- ThrowMsg(Exception::InitFailed, "Error in smack_fsetlabel");
- }
+// if (0 != smack_fsetlabel(sockfd, desc.smackLabel.c_str(), SMACK_LABEL_IPIN)) {
+// LogError("Error in smack_fsetlabel");
+// ThrowMsg(Exception::InitFailed, "Error in smack_fsetlabel");
+// }
} else {
LogInfo("No smack on platform. Socket won't be securied with smack label!");
}
auto &description = CreateDefaultReadSocketDescription(sockfd, false);
- description.isListen = true;
+ description.setListen(true);
description.interfaceID = desc.interfaceID;
description.service = service;
+ description.cynaraPrivilege = desc.privilege;
LogDebug("Listen on socket: " << sockfd <<
" Handler: " << desc.serviceHandlerPath.c_str());
for (int i =0; i < (int)m_socketDescriptionVector.size(); ++i)
{
auto &desc = m_socketDescriptionVector[i];
- if (desc.service == service && desc.isOpen) {
+ if (desc.service == service && desc.isOpen()) {
close(i);
- desc.isOpen = false;
+ desc.setOpen(false);
}
}
ReThrow(Exception::Base);
}
void SocketManager::Close(ConnectionID connectionID) {
- {
- std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
- m_closeQueue.push(connectionID);
- }
- NotifyMe();
+ CloseEvent event;
+ event.sock = connectionID.sock;
+ event.counter = connectionID.counter;
+ AddEvent(event);
}
void SocketManager::Write(ConnectionID connectionID, const RawBuffer &rawBuffer) {
- WriteBuffer buffer;
- buffer.connectionID = connectionID;
- buffer.rawBuffer = rawBuffer;
+ WriteEvent event{connectionID, rawBuffer};
+ AddEvent(event);
+}
+
+void SocketManager::SecurityCheck(ConnectionID connectionID) {
+ SecurityEvent event;
+ event.sock = connectionID.sock;
+ event.counter = connectionID.counter;
+ AddEvent(event);
+}
+
+void SocketManager::CreateEvent(EventFunction fun) {
{
std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
- m_writeBufferQueue.push(buffer);
+ m_eventQueue.push(std::move(fun));
}
NotifyMe();
}
}
void SocketManager::ProcessQueue() {
- WriteBuffer buffer;
- {
- std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
- while (!m_writeBufferQueue.empty()) {
- buffer = m_writeBufferQueue.front();
- m_writeBufferQueue.pop();
+ while(1) {
+ EventFunction fun;
+ {
+ std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
+ if (m_eventQueue.empty())
+ return;
+ fun = std::move(m_eventQueue.front());
+ m_eventQueue.pop();
+ }
+ fun();
+ }
+}
- auto &desc = m_socketDescriptionVector[buffer.connectionID.sock];
+void SocketManager::Handle(const WriteEvent &event) {
+ auto &desc = m_socketDescriptionVector[event.connectionID.sock];
- if (!desc.isOpen) {
- LogDebug("Received packet for write but connection is closed. Packet ignored!");
- continue;
- }
+ if (!desc.isOpen()) {
+ LogDebug("Received packet for write but connection is closed. Packet ignored!");
+ return;
+ }
- if (desc.counter != buffer.connectionID.counter)
- {
- LogDebug("Received packet for write but counter is broken. Packet ignored!");
- continue;
- }
+ if (desc.counter != event.connectionID.counter)
+ {
+ LogDebug("Received packet for write but counter is broken. Packet ignored!");
+ return;
+ }
- std::copy(
- buffer.rawBuffer.begin(),
- buffer.rawBuffer.end(),
- std::back_inserter(desc.rawBuffer));
+ std::copy(
+ event.rawBuffer.begin(),
+ event.rawBuffer.end(),
+ std::back_inserter(desc.rawBuffer));
- FD_SET(buffer.connectionID.sock, &m_writeSet);
- }
+ FD_SET(event.connectionID.sock, &m_writeSet);
+}
- }
+void SocketManager::Handle(const CloseEvent &event) {
+ if (!m_socketDescriptionVector[event.sock].isOpen())
+ return;
- while (1) {
- ConnectionID connection;
- {
- std::lock_guard<std::mutex> ulock(m_eventQueueMutex);
- if (m_closeQueue.empty())
- return;
- connection = m_closeQueue.front();
- m_closeQueue.pop();
- }
+ if (event.counter != m_socketDescriptionVector[event.sock].counter)
+ return;
- if (!m_socketDescriptionVector[connection.sock].isOpen)
- continue;
+ CloseSocket(event.sock);
+}
- if (connection.counter != m_socketDescriptionVector[connection.sock].counter)
- continue;
+void SocketManager::Handle(const SecurityEvent &event) {
+ auto& desc = m_socketDescriptionVector[event.sock];
+ if (!desc.isOpen())
+ return;
- CloseSocket(connection.sock);
- }
+ if (event.counter != desc.counter)
+ return;
+
+ std::string session = std::to_string(desc.counter);
+
+ m_cynara->Request(desc.cynaraUser,
+ desc.cynaraClient,
+ session,
+ desc.cynaraPrivilege,
+ [this, event](bool allowed) {
+ this->SecurityStatus(event.sock, event.counter, allowed);
+ });
}
void SocketManager::CloseSocket(int sock) {
auto &desc = m_socketDescriptionVector[sock];
- if (!(desc.isOpen)) {
+ if (!(desc.isOpen())) {
// This may happend when some information was waiting for write to the
// socket and in the same time socket was closed by the client.
LogError("Socket " << sock << " is not open. Nothing to do!");
event.connectionID.counter = desc.counter;
auto service = desc.service;
- desc.isOpen = false;
+ desc.setOpen(false);
desc.service = NULL;
desc.interfaceID = -1;
desc.rawBuffer.clear();
FD_CLR(sock, &m_writeSet);
}
+void SocketManager::CynaraSocket(int oldFd, int newFd, bool isRW) {
+ if (newFd != oldFd) {
+ if (newFd >= 0) {
+ auto &desc = CreateDefaultReadSocketDescription(newFd, false);
+ desc.service = nullptr;
+ desc.setCynara(true);
+ }
+
+ if (oldFd >= 0) {
+ auto &old = m_socketDescriptionVector[oldFd];
+ old.setOpen(false);
+ old.setCynara(false);
+ FD_CLR(oldFd, &m_writeSet);
+ FD_CLR(oldFd, &m_readSet);
+ }
+ }
+
+ if (newFd >= 0) {
+ FD_SET(newFd, &m_readSet);
+
+ if (isRW)
+ FD_SET(newFd, &m_writeSet);
+ else
+ FD_CLR(newFd, &m_writeSet);
+ }
+}
+
} // namespace CKM
/*
- * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Contact: Bumjin Im <bj.im@samsung.com>
*
#include <string>
#include <mutex>
#include <thread>
+#include <functional>
#include <dpl/exception.h>
namespace CKM {
+class Cynara;
+
class SocketManager : public GenericSocketManager {
public:
class Exception {
DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
DECLARE_EXCEPTION_TYPE(Base, InitFailed)
};
+
+
SocketManager();
virtual ~SocketManager();
virtual void MainLoop();
virtual void MainLoopStop();
+ virtual void CynaraSocket(int oldFd, int newFd, bool isRW);
+ void SecurityStatus(int sock, int counter, bool allowed);
+
virtual void RegisterSocketService(GenericSocketService *service);
virtual void Close(ConnectionID connectionID);
virtual void Write(ConnectionID connectionID, const RawBuffer &rawBuffer);
+ virtual void SecurityCheck(ConnectionID connectionID);
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);
void CloseSocket(int sock);
struct SocketDescription {
- bool isListen;
- bool isOpen;
- bool isTimeout;
+ bool isOpen() { return m_flags & OPEN; }
+ bool isListen() { return m_flags & LISTEN; }
+ bool isCynara() { return m_flags & CYNARA; }
+ bool isTimeout() { return m_flags & TIMEOUT; }
+ void setOpen(bool isSet) { isSet ? m_flags |= OPEN : m_flags &= ~OPEN; }
+ void setListen(bool isSet) { isSet ? m_flags |= LISTEN : m_flags &= ~LISTEN; }
+ void setCynara(bool isSet) { isSet ? m_flags |= CYNARA : m_flags &= ~CYNARA; }
+ void setTimeout(bool isSet) { isSet ? m_flags |= TIMEOUT : m_flags &= ~TIMEOUT; }
+
InterfaceID interfaceID;
GenericSocketService *service;
time_t timeout;
RawBuffer rawBuffer;
int counter;
+ std::string cynaraPrivilege;
+ std::string cynaraUser;
+ std::string cynaraClient;
SocketDescription()
- : isListen(false)
- , isOpen(false)
- , isTimeout(false)
- , interfaceID(-1)
+ : interfaceID(-1)
, service(NULL)
+ , m_flags(0)
{}
+ private:
+ static const char LISTEN = 1 << 0;
+ static const char OPEN = 1 << 1;
+ static const char CYNARA = 1 << 2;
+ static const char TIMEOUT = 1 << 3;
+ int m_flags;
};
SocketDescription& CreateDefaultReadSocketDescription(int sock, bool timeout);
typedef std::vector<SocketDescription> SocketDescriptionVector;
- struct WriteBuffer {
+ // support for generic event Queue
+ typedef std::function<void(void)> EventFunction;
+ template <typename E>
+ void AddEvent(E event) {
+ CreateEvent([this, event]() {this->Handle(event);});
+ }
+ void CreateEvent(EventFunction fun);
+
+ struct WriteEvent {
ConnectionID connectionID;
RawBuffer rawBuffer;
};
+ struct CloseEvent : public ConnectionID {};
+ struct SecurityEvent : public ConnectionID {};
+
+ void Handle(const WriteEvent &event);
+ void Handle(const CloseEvent &event);
+ void Handle(const SecurityEvent &event);
+ // support for generic event Queue
+
struct Timeout {
time_t time;
int sock;
int m_maxDesc;
bool m_working;
std::mutex m_eventQueueMutex;
- std::queue<WriteBuffer> m_writeBufferQueue;
- std::queue<ConnectionID> m_closeQueue;
+ std::queue<EventFunction> m_eventQueue;
int m_notifyMe[2];
int m_counter;
std::priority_queue<Timeout> m_timeoutQueue;
CommMgr m_commMgr;
+ std::unique_ptr<Cynara> m_cynara;
};
} // namespace CKM
LogDebug("Read event");
auto &info = m_connectionInfoMap[event.connectionID.counter];
info.buffer.Push(event.rawBuffer);
- while(ProcessOne(event.connectionID, info));
+
+ if (!info.buffer.Ready())
+ return;
+
+ if (info.checkInProgress)
+ return;
+
+ info.checkInProgress = true;
+ m_serviceManager->SecurityCheck(event.connectionID);
}
void ThreadService::Handle(const CloseEvent &event) {
m_connectionInfoMap.erase(event.connectionID.counter);
}
+void ThreadService::Handle(const SecurityEvent &event) {
+ LogDebug("Security event");
+ auto it = m_connectionInfoMap.find(event.connectionID.counter);
+
+ if (it == m_connectionInfoMap.end()) {
+ LogDebug("Connection has been closed already");
+ return;
+ }
+ auto &info = it->second;
+
+ if (!info.checkInProgress) {
+ LogDebug("Wrong status in info.checkInProgress. Expected: true.");
+ return;
+ }
+
+ ProcessOne(event.connectionID, info, event.allowed);
+
+ if (info.buffer.Ready())
+ m_serviceManager->SecurityCheck(event.connectionID);
+ else
+ info.checkInProgress = false;
+}
+
} /* namespace CKM */
namespace CKM {
-class ThreadService: public CKM::GenericSocketService, public CKM::ServiceThread
+class ThreadService: public GenericSocketService, public ServiceThread
{
public:
ThreadService();
void Event(const WriteEvent& event) { ThreadEvent(event); }
void Event(const ReadEvent& event) { ThreadEvent(event); }
void Event(const CloseEvent& event) { ThreadEvent(event); }
+ void Event(const SecurityEvent &event) { ThreadEvent(event); }
protected:
virtual bool ProcessOne(const ConnectionID &conn,
- ConnectionInfo &info) = 0;
+ ConnectionInfo &info,
+ bool allowed) = 0;
template <typename E>
void ThreadEvent(const E& event) {
CreateEvent([this, event]() { this->Handle(event); });
}
-private:
void Handle(const AcceptEvent &event);
void Handle(const WriteEvent &event);
void Handle(const ReadEvent &event);
void Handle(const CloseEvent &event);
+ void Handle(const SecurityEvent &event);
ConnectionInfoMap m_connectionInfoMap;
};
/*
- * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
GenericSocketService::ServiceDescriptionVector CKMService::GetServiceDescription()
{
return ServiceDescriptionVector {
- {SERVICE_SOCKET_CKM_CONTROL, "key-manager::api-control", SOCKET_ID_CONTROL},
- {SERVICE_SOCKET_CKM_STORAGE, "key-manager::api-storage", SOCKET_ID_STORAGE}
+ {SERVICE_SOCKET_CKM_CONTROL, "http://tizen.org/privilege/keymanager.admin", SOCKET_ID_CONTROL},
+ {SERVICE_SOCKET_CKM_STORAGE, "http://tizen.org/privilege/keymanager", SOCKET_ID_STORAGE}
};
}
Register(*manager);
}
+// CKMService does not support security check
+// so 3rd parameter is not used
bool CKMService::ProcessOne(
const ConnectionID &conn,
- ConnectionInfo &info)
+ ConnectionInfo &info,
+ bool /*allowed*/)
{
LogDebug ("process One");
RawBuffer response;
}
}
+void CKMService::CustomHandle(const ReadEvent &event) {
+ LogDebug("Read event");
+ auto &info = m_connectionInfoMap[event.connectionID.counter];
+ info.buffer.Push(event.rawBuffer);
+ while(ProcessOne(event.connectionID, info, true));
+}
+
+void CKMService::CustomHandle(const SecurityEvent & /*event*/) {
+ LogError("This should not happend! SecurityEvent was called on CKMService!");
+}
+
} // namespace CKM
/*
- * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
CKMService& operator=(const CKMService &) = delete;
CKMService& operator=(CKMService &&) = delete;
+ // Custom add custom support for ReadEvent and SecurityEvent
+ // because we want to bypass security check in CKMService
+ virtual void Event(const ReadEvent &event) {
+ CreateEvent([this, event]() { this->CustomHandle(event); });
+ }
+
+ virtual void Event(const SecurityEvent &event) {
+ CreateEvent([this, event]() { this->CustomHandle(event); });
+ }
+
virtual void Start(void);
virtual void Stop(void);
ServiceDescriptionVector GetServiceDescription();
+protected:
+ // CustomHandle is used to bypass security check
+ void CustomHandle(const ReadEvent &event);
+ void CustomHandle(const SecurityEvent &event);
+
private:
virtual void SetCommManager(CommMgr *manager);
bool ProcessOne(
const ConnectionID &conn,
- ConnectionInfo &info);
+ ConnectionInfo &info,
+ bool allowed);
RawBuffer ProcessControl(
MessageBuffer &buffer);
GenericSocketService::ServiceDescriptionVector EncryptionService::GetServiceDescription()
{
return ServiceDescriptionVector {
- {SERVICE_SOCKET_ENCRYPTION, "key-manager::api-encryption", SOCKET_ID_ENCRYPTION}
+ {SERVICE_SOCKET_ENCRYPTION, "http://tizen.org/privilege/keymanager", SOCKET_ID_ENCRYPTION}
};
}
Register(*manager);
}
+// Encryption Service does not support any kind of security-check
+// and 3rd parameter is not required
bool EncryptionService::ProcessOne(
const ConnectionID &conn,
- ConnectionInfo &info)
+ ConnectionInfo &info,
+ bool /*allowed*/)
{
LogDebug ("process One");
try {
m_logic.Crypt(req);
}
+void EncryptionService::CustomHandle(const ReadEvent &event) {
+ LogDebug("Read event");
+ auto &info = m_connectionInfoMap[event.connectionID.counter];
+ info.buffer.Push(event.rawBuffer);
+ while(ProcessOne(event.connectionID, info, true));
+}
+
+void EncryptionService::CustomHandle(const SecurityEvent &/*event*/) {
+ LogError("This should not happend! SecurityEvent was called on EncryptionService!");
+}
+
} /* namespace CKM */
// from ThreadService
ServiceDescriptionVector GetServiceDescription();
+ // Custom add custom support for ReadEvent and SecurityEvent
+ // because we want to bypass security check in EncryptionService
+ virtual void Event(const ReadEvent &event) {
+ CreateEvent([this, event]() { this->CustomHandle(event); });
+ }
+
+ virtual void Event(const SecurityEvent &event) {
+ CreateEvent([this, event]() { this->CustomHandle(event); });
+ }
+
void Start();
void Stop();
+protected:
+ // CustomHandle is used to bypass security check
+ void CustomHandle(const ReadEvent &event);
+ void CustomHandle(const SecurityEvent &event);
+
private:
virtual void SetCommManager(CommMgr *manager);
- bool ProcessOne(const ConnectionID &conn, ConnectionInfo &info);
+ bool ProcessOne(const ConnectionID &conn, ConnectionInfo &info, bool allowed);
void ProcessMessage(MsgKeyResponse msg);
void ProcessEncryption(const ConnectionID &conn,
const Credentials &cred,
/*
- * Copyright (c) 2014 Samsung Electronics Co.
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
m_isNetAvailable = false;
}
-RawBuffer OCSPLogic::ocspCheck(int commandId, const RawBufferVector &rawChain) {
+RawBuffer OCSPLogic::ocspCheck(int commandId, const RawBufferVector &rawChain, bool allowed) {
CertificateImplVector certChain;
OCSPModule ocsp;
int retCode = CKM_API_SUCCESS;
if (!m_isNetAvailable) {
retCode = CKM_API_ERROR_NOT_SUPPORTED;
+ } else if (!allowed) {
+ retCode = CKM_API_ERROR_ACCESS_DENIED;
+ } else if(rawChain.size() < 2) {
+ LogError("Certificate chain should contain at least 2 certificates");
+ retCode = CKM_API_ERROR_INPUT_PARAM;
} else {
- if (rawChain.size() < 2) {
- LogError("Certificate chain should contain at least 2 certificates");
- retCode = CKM_API_ERROR_INPUT_PARAM;
- } else {
- for (auto &e: rawChain) {
- certChain.push_back(CertificateImpl(e, DataFormat::FORM_DER));
- if (certChain.rbegin()->empty()) {
- LogDebug("Error in parsing certificates!");
- retCode = CKM_API_ERROR_INPUT_PARAM;
- break;
- }
+ for (auto &e: rawChain) {
+ certChain.push_back(CertificateImpl(e, DataFormat::FORM_DER));
+ if (certChain.rbegin()->empty()) {
+ LogDebug("Error in parsing certificates!");
+ retCode = CKM_API_ERROR_INPUT_PARAM;
+ break;
}
}
}
/*
- * Copyright (c) 2014 Samsung Electronics Co.
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
OCSPLogic& operator=(const OCSPLogic &) = delete;
OCSPLogic& operator=(OCSPLogic &&) = delete;
- RawBuffer ocspCheck(int commandId, const RawBufferVector &rawChain);
+ RawBuffer ocspCheck(int commandId, const RawBufferVector &rawChain, bool allowed);
virtual ~OCSPLogic(){}
private:
void setNetAvailable();
/*
- * Copyright (c) 2014 Samsung Electronics Co.
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
GenericSocketService::ServiceDescriptionVector OCSPService::GetServiceDescription()
{
return ServiceDescriptionVector {
- {SERVICE_SOCKET_OCSP, "key-manager::api-ocsp", SOCKET_ID_OCSP}
+ {SERVICE_SOCKET_OCSP, "http://tizen.org/privilege/internet", SOCKET_ID_OCSP}
};
}
bool OCSPService::ProcessOne(
const ConnectionID &conn,
- ConnectionInfo &info)
+ ConnectionInfo &info,
+ bool allowed)
{
LogDebug ("process One");
RawBufferVector chainVector;
buffer.Deserialize(commandId, chainVector);
- RawBuffer response = m_logic->ocspCheck(commandId, chainVector);
+ RawBuffer response = m_logic->ocspCheck(commandId, chainVector, allowed);
m_serviceManager->Write(conn, response);
return true;
/*
- * Copyright (c) 2014 Samsung Electronics Co.
+ * Copyright (c) 2014 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
private:
bool ProcessOne(
const ConnectionID &conn,
- ConnectionInfo &info);
+ ConnectionInfo &info,
+ bool allowed);
OCSPLogic *m_logic;
};
capi-system-info
vconf
libxml-2.0
+ cynara-client-async
+ cynara-creds-socket
)
FIND_PACKAGE(Threads REQUIRED)
${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/db-crypto-ext.cpp
${PROJECT_SOURCE_DIR}/tools/ckm_db_tool/ckm-logic-ext.cpp
+ ${KEY_MANAGER_PATH}/main/cynara.cpp
${KEY_MANAGER_PATH}/main/generic-socket-manager.cpp
${KEY_MANAGER_PATH}/main/socket-manager.cpp
${KEY_MANAGER_PATH}/main/smack-check.cpp