Run Security Containers Server as non root user
[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
29 #include "log/logger.hpp"
30 #include "utils/paths.hpp"
31 #include "config/manager.hpp"
32
33 #include <boost/filesystem.hpp>
34
35 #include <string>
36 #include <thread>
37
38
39 namespace security_containers {
40
41 namespace fs = boost::filesystem;
42
43 namespace {
44
45 typedef std::lock_guard<std::recursive_mutex> Lock;
46
47 // TODO: move constants to the config file when default values are implemented there
48 const int RECONNECT_RETRIES = 15;
49 const int RECONNECT_DELAY = 1 * 1000;
50
51 } // namespace
52
53 Container::Container(const std::string& containerConfigPath,
54                      const std::string& baseRunMountPointPath)
55 {
56     config::loadFromFile(containerConfigPath, mConfig);
57
58     for (std::string r: mConfig.permittedToSend) {
59         mPermittedToSend.push_back(boost::regex(r));
60     }
61     for (std::string r: mConfig.permittedToRecv) {
62         mPermittedToRecv.push_back(boost::regex(r));
63     }
64
65     const std::string baseConfigPath = utils::dirName(containerConfigPath);
66     mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string();
67     mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string();
68     if (!mConfig.runMountPoint.empty()) {
69         mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string();
70     }
71
72     LOGT("Creating Network Admin " << mConfig.networkConfig);
73     mNetworkAdmin.reset(new NetworkAdmin(mConfig));
74     LOGT("Creating Container Admin " << mConfig.config);
75     mAdmin.reset(new ContainerAdmin(mConfig));
76 }
77
78 Container::~Container()
79 {
80     // Make sure all OnNameLostCallbacks get finished and no new will
81     // get called before proceeding further. This guarantees no race
82     // condition on the mReconnectThread.
83     {
84         Lock lock(mReconnectMutex);
85         mConnection.reset();
86     }
87
88     if (mReconnectThread.joinable()) {
89         mReconnectThread.join();
90     }
91 }
92
93 const std::vector<boost::regex>& Container::getPermittedToSend() const
94 {
95     return mPermittedToSend;
96 }
97
98 const std::vector<boost::regex>& Container::getPermittedToRecv() const
99 {
100     return mPermittedToRecv;
101 }
102
103 const std::string& Container::getId() const
104 {
105     Lock lock(mReconnectMutex);
106     return mAdmin->getId();
107 }
108
109 int Container::getPrivilege() const
110 {
111     return mConfig.privilege;
112 }
113
114 void Container::start()
115 {
116     Lock lock(mReconnectMutex);
117     mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint));
118     mNetworkAdmin->start();
119     mAdmin->start();
120     mConnection.reset(new ContainerConnection(mConnectionTransport->acquireAddress(),
121                                               std::bind(&Container::onNameLostCallback, this)));
122     if (mNotifyCallback) {
123         mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
124     }
125     if (mDisplayOffCallback) {
126         mConnection->setDisplayOffCallback(mDisplayOffCallback);
127     }
128     if (mFileMoveCallback) {
129         mConnection->setFileMoveRequestCallback(mFileMoveCallback);
130     }
131
132     // Send to the background only after we're connected,
133     // otherwise it'd take ages.
134     LOGD(getId() << ": DBUS connected, sending to the background");
135     goBackground();
136 }
137
138 void Container::stop()
139 {
140     Lock lock(mReconnectMutex);
141     mConnection.reset();
142     mAdmin->stop();
143     mNetworkAdmin->stop();
144     mConnectionTransport.reset();
145 }
146
147 void Container::goForeground()
148 {
149     Lock lock(mReconnectMutex);
150     mAdmin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
151 }
152
153 void Container::goBackground()
154 {
155     Lock lock(mReconnectMutex);
156     mAdmin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
157 }
158
159 void Container::setDetachOnExit()
160 {
161     Lock lock(mReconnectMutex);
162     mNetworkAdmin->setDetachOnExit();
163     mAdmin->setDetachOnExit();
164     mConnectionTransport->setDetachOnExit();
165 }
166
167 bool Container::isRunning()
168 {
169     Lock lock(mReconnectMutex);
170     return mAdmin->isRunning();
171 }
172
173 bool Container::isStopped()
174 {
175     Lock lock(mReconnectMutex);
176     return mAdmin->isStopped();
177 }
178
179 bool Container::isPaused()
180 {
181     Lock lock(mReconnectMutex);
182     return mAdmin->isPaused();
183 }
184
185 void Container::onNameLostCallback()
186 {
187     LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting...");
188
189     if (mReconnectThread.joinable()) {
190         mReconnectThread.join();
191     }
192     mReconnectThread = std::thread(std::bind(&Container::reconnectHandler, this));
193 }
194
195 void Container::reconnectHandler()
196 {
197     {
198         Lock lock(mReconnectMutex);
199         mConnection.reset();
200     }
201
202     for (int i = 0; i < RECONNECT_RETRIES; ++i) {
203         // This sleeps even before the first try to give DBUS some time to come back up
204         std::this_thread::sleep_for(std::chrono::milliseconds(RECONNECT_DELAY));
205
206         Lock lock(mReconnectMutex);
207         if (isStopped()) {
208             LOGI(getId() << ": Has stopped, nothing to reconnect to, bailing out");
209             return;
210         }
211
212         try {
213             LOGT(getId() << ": Reconnect try " << i + 1);
214             mConnection.reset(new ContainerConnection(mConnectionTransport->acquireAddress(),
215                                                       std::bind(&Container::onNameLostCallback, this)));
216             LOGI(getId() << ": Reconnected");
217             return;
218         } catch (SecurityContainersException&) {
219             LOGT(getId() << ": Reconnect try " << i + 1 << " has been unsuccessful");
220         }
221     }
222
223     LOGE(getId() << ": Reconnecting to the DBUS has failed, stopping the container");
224     stop();
225 }
226
227 void Container::setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback)
228 {
229     Lock lock(mReconnectMutex);
230     mNotifyCallback = callback;
231     if (mConnection) {
232         mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
233     }
234 }
235
236 void Container::sendNotification(const std::string& container,
237                                  const std::string& application,
238                                  const std::string& message)
239 {
240     Lock lock(mReconnectMutex);
241     if (mConnection) {
242         mConnection->sendNotification(container, application, message);
243     } else {
244         LOGE(getId() << ": Can't send notification, no connection to DBUS");
245     }
246 }
247
248 void Container::setDisplayOffCallback(const DisplayOffCallback& callback)
249 {
250     Lock lock(mReconnectMutex);
251
252     mDisplayOffCallback = callback;
253     if (mConnection) {
254         mConnection->setDisplayOffCallback(callback);
255     }
256 }
257
258 void Container::setFileMoveRequestCallback(const FileMoveRequestCallback& callback)
259 {
260     Lock lock(mReconnectMutex);
261
262     mFileMoveCallback = callback;
263     if (mConnection) {
264         mConnection->setFileMoveRequestCallback(callback);
265     }
266 }
267
268
269 } // namespace security_containers