2 * Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
16 #include <cynara-client.h>
17 #include <sys/smack.h>
25 #include "file-sink.h"
26 #include "secure-erase.h"
27 #include "internal-encryption.h"
28 #include "external-encryption.h"
30 #include "key-server.h"
31 #include "key-manager/key-generator.h"
34 using namespace std::placeholders;
36 audit::LogSink *SINK = nullptr;
42 std::unique_ptr<FileLogSink> _sink = nullptr;
44 void dbusBusAcquired(GDBusConnection *connection, const gchar *, gpointer user_data)
46 DEBUG(SINK, "dbusBusAcquired");
48 auto self = static_cast<ServerContext*>(user_data);
49 self->dbusRegisterObjects(connection);
54 * dbus-send --system --dest=org.freedesktop.DBus --type=method_call --print-reply
55 * /org/freedesktop/DBus org.freedesktop.DBus.ListNames
57 void dbusNameAcquired(GDBusConnection *, const gchar *, gpointer )
59 DEBUG(SINK, "dbusNameAcquired");
62 void dbusNameLost(GDBusConnection *, const gchar *, gpointer user_data)
64 DEBUG(SINK, "dbusNameLost");
65 static_cast<ServerContext*>(user_data)->stop();
70 void ServerContext::dbusRegisterObjects(GDBusConnection *connection)
72 externalEncryption->dbusRegisterObject(connection);
76 * Timer thread fuction responsible for detecting a server inactivity period after which it will be
79 * Assumptions & acknowledgements:
80 * - Currently there are only 2 ways of stopping the oded server:
81 * - Timeout expiration implemented in the function below
82 * - Terminating with a signal (e.g. SIGTERM from systemd)
83 * - There's a risk of race condition for a request that has just been received (the program is
84 * somewhere between klay's epoll_wait() and mutex lock in ServerContext::requestStarted) while
85 * the timerFunc below detects the timeout and stops the server. In such case the newly received
86 * request will not be processed and client will be disconnected. For now this risk is accepted.
87 * To reduce it, the klay's socket & thread handling would have to be modified or replaced.
88 * - Request processing callbacks are currently called from one of klay's worker threads.
89 * - For requests that require longer processing additional threads are spawned by the server. The
90 * server is considered active as long as the request processing thread is running.
91 * - For debugging purpose, a manually started server is not considered inactive until a request
92 * arrives. In other words, the inactivity time measurement starts after a request is processed.
93 * - Spurious wakeups will not occur in sleep_for().
95 void ServerContext::timerFunc()
97 DEBUG(SINK, "Timer thread started");
98 bool requestArrived = false;
100 std::this_thread::sleep_for(std::chrono::seconds(5));
102 std::lock_guard<std::mutex> lock(timerMutex);
103 if (!requestArrived) {
107 requestArrived = true;
109 if (!newRequests && currentRequests == 0)
114 INFO(SINK, "Timeout reached. ODE server stopping.");
119 // This method may be called from different threads
120 void ServerContext::requestStarted()
122 std::lock_guard<std::mutex> lock(timerMutex);
125 DEBUG(SINK, "New request received. Current count: " << currentRequests);
128 // This method may be called from different threads
129 void ServerContext::requestFinished()
131 std::lock_guard<std::mutex> lock(timerMutex);
132 assert(currentRequests > 0);
134 DEBUG(SINK, "Request processed. Current count:" << currentRequests);
137 ServerContext::ServerContext() : rmi::Service(SOCKET_PATH), currentRequests(0), newRequests(false)
139 _sink.reset(new FileLogSink("ode.log"));
142 INFO(SINK, "ODE server starting.");
144 setPrivilegeChecker(std::bind(&ServerContext::checkPeerPrivilege, this, _1, _2));
146 keys.reset(new KeyServer(*this));
148 secureErase.reset(new SecureEraseServer(*this));
149 internalEncryption.reset(new InternalEncryptionServer(*this, *keys));
150 externalEncryption.reset(new ExternalEncryptionServer(*this, *keys));
151 luks.reset(new LuksServer(*this, *keys));
153 KeyGenerator::init();
155 guint dbusOwnerId = g_bus_own_name(G_BUS_TYPE_SYSTEM,
157 G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE,
164 if (dbusOwnerId == 0)
165 throw runtime::Exception("Dbus failed to own name");
167 EventNotifier::init();
169 std::thread timerThread(&ServerContext::timerFunc, this);
170 timerThread.detach();
173 ServerContext::~ServerContext()
175 KeyGenerator::cleanup();
178 bool ServerContext::checkPeerPrivilege(const rmi::Credentials& cred, const std::string& privilege)
182 if (privilege.empty()) {
186 if (::cynara_initialize(&p_cynara, NULL) != CYNARA_API_SUCCESS) {
187 ERROR(SINK, "Failure in cynara API");
191 std::string uid = std::to_string(cred.uid);
192 if (::cynara_check(p_cynara, cred.security.c_str(), "",
194 privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) {
195 ::cynara_finish(p_cynara);
196 ERROR(SINK, "Access denied: " + cred.security + " : " + privilege);
200 ::cynara_finish(p_cynara);