5c3420da4f7a79b1aecb25dc537c596e9960b8fb
[platform/core/security/vasum.git] / server / server.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak (j.olszak@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  Jan Olszak (j.olszak@samsung.com)
22  * @brief   Server class definition
23  */
24
25 #include "config.hpp"
26
27 #include "server.hpp"
28 #include "containers-manager.hpp"
29 #include "exception.hpp"
30
31 #include "config/manager.hpp"
32 #include "logger/logger.hpp"
33 #include "utils/glib-loop.hpp"
34 #include "utils/environment.hpp"
35 #include "utils/fs.hpp"
36
37 #include <csignal>
38 #include <cerrno>
39 #include <string>
40 #include <cstring>
41 #include <atomic>
42 #include <unistd.h>
43 #include <cap-ng.h>
44 #include <pwd.h>
45 #include <sys/stat.h>
46 #include <boost/filesystem.hpp>
47
48
49 #ifndef SECURITY_CONTAINERS_USER
50 #error "SECURITY_CONTAINERS_USER must be defined!"
51 #endif
52
53 #ifndef INPUT_EVENT_GROUP
54 #error "INPUT_EVENT_GROUP must be defined!"
55 #endif
56
57 #ifndef LIBVIRT_GROUP
58 #error "LIBVIRT_GROUP must be defined!"
59 #endif
60
61 extern char** environ;
62
63 namespace security_containers {
64
65
66 Server::Server(const std::string& configPath, bool runAsRoot)
67     : mConfigPath(configPath)
68 {
69     if (!prepareEnvironment(configPath, runAsRoot)) {
70         throw ServerException("Environment setup failed");
71     }
72 }
73
74
75 Server::~Server()
76 {
77 }
78
79
80 namespace {
81
82 std::atomic_bool gUpdateTriggered(false);
83 utils::Latch gSignalLatch;
84
85 void signalHandler(const int sig)
86 {
87     LOGI("Got signal " << sig);
88
89     if (sig == SIGUSR1) {
90         LOGD("Received SIGUSR1 - triggering update.");
91         gUpdateTriggered = true;
92     }
93
94     gSignalLatch.set();
95 }
96
97 } // namespace
98
99 void Server::run()
100 {
101     signal(SIGINT,  signalHandler);
102     signal(SIGTERM, signalHandler);
103     signal(SIGUSR1, signalHandler);
104
105     LOGI("Starting daemon...");
106     {
107         utils::ScopedGlibLoop loop;
108         ContainersManager manager(mConfigPath);
109
110         manager.startAll();
111         LOGI("Daemon started");
112
113         gSignalLatch.wait();
114
115         // Detach containers if we triggered an update
116         if (gUpdateTriggered) {
117             manager.setContainersDetachOnExit();
118         }
119
120         LOGI("Stopping daemon...");
121         // manager.stopAll() will be called in destructor
122     }
123     LOGI("Daemon stopped");
124 }
125
126 void Server::reloadIfRequired(char* argv[])
127 {
128     if (gUpdateTriggered) {
129         execve(argv[0], argv, environ);
130
131         LOGE("Failed to reload " << argv[0] << ": " << strerror(errno));
132     }
133 }
134
135 void Server::terminate()
136 {
137     LOGI("Terminating server");
138     gSignalLatch.set();
139 }
140
141 bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
142 {
143     namespace fs = boost::filesystem;
144
145     // TODO: currently this config is loaded twice: here and in ContainerManager
146     ContainersManagerConfig config;
147     config::loadFromFile(configPath, config);
148
149     struct passwd* pwd = ::getpwnam(SECURITY_CONTAINERS_USER);
150     if (pwd == NULL) {
151         LOGE("getpwnam failed to find user '" << SECURITY_CONTAINERS_USER << "'");
152         return false;
153     }
154     uid_t uid = pwd->pw_uid;
155     gid_t gid = pwd->pw_gid;
156     LOGD("security-containers UID = " << uid << ", GID = " << gid);
157
158     // create directory for dbus socket (if needed)
159     if (!config.runMountPointPrefix.empty()) {
160         if (!utils::createDir(config.runMountPointPrefix, uid, gid,
161                               fs::perms::owner_all |
162                               fs::perms::group_read | fs::perms::group_exe |
163                               fs::perms::others_read | fs::perms::others_exe)) {
164             return false;
165         }
166     }
167
168     // Omit supplementaty group setup and root drop if the user is already switched.
169     // This situation will happen during daemon update triggered by SIGUSR1.
170     if (!runAsRoot && geteuid() == uid) {
171         return true;
172     }
173
174     // LIBVIRT_GROUP provides access to libvirt's daemon socket.
175     // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor.
176     if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP})) {
177         return false;
178     }
179
180     // CAP_SYS_ADMIN allows to mount tmpfs' for dbus communication at the runtime.
181     // NOTE: CAP_MAC_OVERRIDE is temporary and must be removed when "smack namespace"
182     // is introduced. The capability is needed to allow modify SMACK labels of
183     // "/var/run/containers/<container>/run" mount point.
184     return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, CAP_MAC_OVERRIDE}));
185 }
186
187
188 } // namespace security_containers