60d124e9e277c79ff967bf8ecc4dea0e9bc72de3
[platform/core/security/vasum.git] / server / container.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
22  * @brief   Implementation of class for managing one container
23  */
24
25 #include "config.hpp"
26
27 #include "container.hpp"
28 #include "base-exception.hpp"
29
30 #include "logger/logger.hpp"
31 #include "utils/paths.hpp"
32 #include "config/manager.hpp"
33
34 #include <boost/filesystem.hpp>
35
36 #include <string>
37 #include <thread>
38
39
40 namespace security_containers {
41
42 namespace fs = boost::filesystem;
43
44 namespace {
45
46 typedef std::lock_guard<std::recursive_mutex> Lock;
47
48 // TODO: move constants to the config file when default values are implemented there
49 const int RECONNECT_RETRIES = 15;
50 const int RECONNECT_DELAY = 1 * 1000;
51
52 } // namespace
53
54 Container::Container(const std::string& containerConfigPath,
55                      const std::string& baseRunMountPointPath)
56 {
57     config::loadFromFile(containerConfigPath, mConfig);
58
59     for (std::string r: mConfig.permittedToSend) {
60         mPermittedToSend.push_back(boost::regex(r));
61     }
62     for (std::string r: mConfig.permittedToRecv) {
63         mPermittedToRecv.push_back(boost::regex(r));
64     }
65
66     const std::string baseConfigPath = utils::dirName(containerConfigPath);
67     mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string();
68     mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string();
69     mConfig.networkFilterConfig = fs::absolute(mConfig.networkFilterConfig,
70                                                baseConfigPath).string();
71     if (!mConfig.runMountPoint.empty()) {
72         mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string();
73     }
74
75     LOGT("Creating Network Admin " << mConfig.networkConfig);
76     mNetworkAdmin.reset(new NetworkAdmin(mConfig));
77     LOGT("Creating Container Admin " << mConfig.config);
78     mAdmin.reset(new ContainerAdmin(mConfig));
79 }
80
81 Container::~Container()
82 {
83     // Make sure all OnNameLostCallbacks get finished and no new will
84     // get called before proceeding further. This guarantees no race
85     // condition on the mReconnectThread.
86     {
87         Lock lock(mReconnectMutex);
88         disconnect();
89     }
90
91     if (mReconnectThread.joinable()) {
92         mReconnectThread.join();
93     }
94 }
95
96 const std::vector<boost::regex>& Container::getPermittedToSend() const
97 {
98     return mPermittedToSend;
99 }
100
101 const std::vector<boost::regex>& Container::getPermittedToRecv() const
102 {
103     return mPermittedToRecv;
104 }
105
106 const std::string& Container::getId() const
107 {
108     Lock lock(mReconnectMutex);
109     return mAdmin->getId();
110 }
111
112 int Container::getPrivilege() const
113 {
114     return mConfig.privilege;
115 }
116
117 void Container::start()
118 {
119     Lock lock(mReconnectMutex);
120     if (mConfig.enableDbusIntegration) {
121         mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint));
122     }
123     mNetworkAdmin->start();
124     mAdmin->start();
125     if (mConfig.enableDbusIntegration) {
126         connect();
127     }
128
129     // Send to the background only after we're connected, otherwise it'd take ages.
130     LOGD(getId() << ": sending to the background");
131     goBackground();
132 }
133
134 void Container::stop()
135 {
136     Lock lock(mReconnectMutex);
137     disconnect();
138     mAdmin->stop();
139     mNetworkAdmin->stop();
140     mConnectionTransport.reset();
141 }
142
143 void Container::connect()
144 {
145     // assume called under reconnect lock
146     mDbusAddress = mConnectionTransport->acquireAddress();
147     mConnection.reset(new ContainerConnection(mDbusAddress,
148                                               std::bind(&Container::onNameLostCallback, this)));
149     if (mNotifyCallback) {
150         mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
151     }
152     if (mDisplayOffCallback) {
153         mConnection->setDisplayOffCallback(mDisplayOffCallback);
154     }
155     if (mFileMoveCallback) {
156         mConnection->setFileMoveRequestCallback(mFileMoveCallback);
157     }
158     if (mProxyCallCallback) {
159         mConnection->setProxyCallCallback(mProxyCallCallback);
160     }
161     if (mDbusStateChangedCallback) {
162         mDbusStateChangedCallback(mDbusAddress);
163     }
164 }
165
166 void Container::disconnect()
167 {
168     // assume called under reconnect lock
169     if (mConnection) {
170         mConnection.reset();
171         mDbusAddress.clear();
172         if (mDbusStateChangedCallback) {
173             // notify about invalid dbusAddress for this container
174             mDbusStateChangedCallback(std::string());
175         }
176     }
177 }
178
179 std::string Container::getDbusAddress()
180 {
181     Lock lock(mReconnectMutex);
182     return mDbusAddress;
183 }
184
185 void Container::goForeground()
186 {
187     Lock lock(mReconnectMutex);
188     mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
189 }
190
191 void Container::goBackground()
192 {
193     Lock lock(mReconnectMutex);
194     mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
195 }
196
197 void Container::setDetachOnExit()
198 {
199     Lock lock(mReconnectMutex);
200     mNetworkAdmin->setDetachOnExit();
201     mAdmin->setDetachOnExit();
202     if (mConnectionTransport) {
203         mConnectionTransport->setDetachOnExit();
204     }
205 }
206
207 bool Container::isRunning()
208 {
209     Lock lock(mReconnectMutex);
210     return mAdmin->isRunning();
211 }
212
213 bool Container::isStopped()
214 {
215     Lock lock(mReconnectMutex);
216     return mAdmin->isStopped();
217 }
218
219 bool Container::isPaused()
220 {
221     Lock lock(mReconnectMutex);
222     return mAdmin->isPaused();
223 }
224
225 bool Container::isSwitchToDefaultAfterTimeoutAllowed() const
226 {
227     return mConfig.switchToDefaultAfterTimeout;
228 }
229
230 void Container::onNameLostCallback()
231 {
232     LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting...");
233
234     if (mReconnectThread.joinable()) {
235         mReconnectThread.join();
236     }
237     mReconnectThread = std::thread(std::bind(&Container::reconnectHandler, this));
238 }
239
240 void Container::reconnectHandler()
241 {
242     {
243         Lock lock(mReconnectMutex);
244         disconnect();
245     }
246
247     for (int i = 0; i < RECONNECT_RETRIES; ++i) {
248         // This sleeps even before the first try to give DBUS some time to come back up
249         std::this_thread::sleep_for(std::chrono::milliseconds(RECONNECT_DELAY));
250
251         Lock lock(mReconnectMutex);
252         if (isStopped()) {
253             LOGI(getId() << ": Has stopped, nothing to reconnect to, bailing out");
254             return;
255         }
256
257         try {
258             LOGT(getId() << ": Reconnect try " << i + 1);
259             connect();
260             LOGI(getId() << ": Reconnected");
261             return;
262         } catch (SecurityContainersException&) {
263             LOGT(getId() << ": Reconnect try " << i + 1 << " has been unsuccessful");
264         }
265     }
266
267     LOGE(getId() << ": Reconnecting to the DBUS has failed, stopping the container");
268     stop();
269 }
270
271 void Container::setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback)
272 {
273     Lock lock(mReconnectMutex);
274     mNotifyCallback = callback;
275     if (mConnection) {
276         mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
277     }
278 }
279
280 void Container::sendNotification(const std::string& container,
281                                  const std::string& application,
282                                  const std::string& message)
283 {
284     Lock lock(mReconnectMutex);
285     if (mConnection) {
286         mConnection->sendNotification(container, application, message);
287     } else {
288         LOGE(getId() << ": Can't send notification, no connection to DBUS");
289     }
290 }
291
292 void Container::setDisplayOffCallback(const DisplayOffCallback& callback)
293 {
294     Lock lock(mReconnectMutex);
295
296     mDisplayOffCallback = callback;
297     if (mConnection) {
298         mConnection->setDisplayOffCallback(callback);
299     }
300 }
301
302 void Container::setFileMoveRequestCallback(const FileMoveRequestCallback& callback)
303 {
304     Lock lock(mReconnectMutex);
305
306     mFileMoveCallback = callback;
307     if (mConnection) {
308         mConnection->setFileMoveRequestCallback(callback);
309     }
310 }
311
312 void Container::setProxyCallCallback(const ProxyCallCallback& callback)
313 {
314     Lock lock(mReconnectMutex);
315
316     mProxyCallCallback = callback;
317     if (mConnection) {
318         mConnection->setProxyCallCallback(callback);
319     }
320 }
321
322 void Container::setDbusStateChangedCallback(const DbusStateChangedCallback& callback)
323 {
324     mDbusStateChangedCallback = callback;
325 }
326
327 void Container::proxyCallAsync(const std::string& busName,
328                                const std::string& objectPath,
329                                const std::string& interface,
330                                const std::string& method,
331                                GVariant* parameters,
332                                const dbus::DbusConnection::AsyncMethodCallCallback& callback)
333 {
334     Lock lock(mReconnectMutex);
335     if (mConnection) {
336         mConnection->proxyCallAsync(busName,
337                                     objectPath,
338                                     interface,
339                                     method,
340                                     parameters,
341                                     callback);
342     } else {
343         LOGE(getId() << ": Can't do a proxy call, no connection to DBUS");
344     }
345 }
346
347
348 } // namespace security_containers