Fix compilation with GCC 4.7
[platform/core/security/nether.git] / src / nether_Manager.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Roman Kubiak (r.kubiak@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  Roman Kubiak (r.kubiak@samsung.com)
22  * @brief   Manager class implementation for nether
23  */
24
25 #include "nether_Manager.h"
26 #include "nether_CynaraBackend.h"
27 #include "nether_FileBackend.h"
28 #include "nether_DummyBackend.h"
29
30 NetherManager::NetherManager(const NetherConfig &_netherConfig)
31         :       netherPrimaryPolicyBackend(nullptr),
32                 netherBackupPolicyBackend(nullptr),
33                 netherFallbackPolicyBackend(nullptr),
34                 netherConfig(_netherConfig)
35 {
36         netherNetlink               = std::unique_ptr<NetherNetlink> (new NetherNetlink(netherConfig));
37         netherNetlink->setListener(this);
38
39         netherPrimaryPolicyBackend      = std::unique_ptr<NetherPolicyBackend> (getPolicyBackend(netherConfig));
40         netherPrimaryPolicyBackend->setListener(this);
41
42         netherBackupPolicyBackend   = std::unique_ptr<NetherPolicyBackend> (getPolicyBackend(netherConfig, false));
43         netherBackupPolicyBackend->setListener(this);
44
45         netherFallbackPolicyBackend = std::unique_ptr<NetherPolicyBackend> (new NetherDummyBackend(netherConfig));
46 }
47
48 NetherManager::~NetherManager() noexcept(true)
49 {
50         close(signalDescriptor);
51 }
52
53 bool NetherManager::initialize()
54 {
55         sigemptyset(&signalMask);
56         sigaddset(&signalMask, SIGHUP);
57
58         if(sigprocmask(SIG_BLOCK, &signalMask, NULL) == -1)
59         {
60                 LOGE("Failed to block signals sigprocmask()");
61                 return (false);
62         }
63
64         signalDescriptor = signalfd(-1, &signalMask, 0);
65         if(signalDescriptor == -1)
66         {
67                 LOGE("Failed acquire signalfd descriptor");
68                 return (false);
69         }
70
71 #ifdef HAVE_AUDIT
72         if(netherConfig.enableAudit)
73         {
74                 if((auditDescriptor = audit_open()) == -1)
75                 {
76                         LOGE("Failed to open an audit netlink socket: " << strerror(errno));
77                         return (false);
78                 }
79
80                 if(audit_set_enabled(auditDescriptor, 1) <= 0)
81                 {
82                         LOGE("Failed to enable auditing: " << strerror(errno));
83                         return (false);
84                 }
85                 else
86                 {
87                         LOGD("Auditing enabled");
88                 }
89         }
90 #endif // HAVE_AUDIT
91
92         if(!netherNetlink->initialize())
93         {
94                 LOGE("Failed to initialize netlink subsystem, exiting");
95                 return (false);
96         }
97
98         if(!netherPrimaryPolicyBackend->initialize())
99         {
100                 LOGE("Failed to initialize primary policy backend, exiting");
101                 return (false);
102         }
103
104         if(!netherBackupPolicyBackend->initialize())
105         {
106                 LOGE("Failed to initialize backup backend, exiting");
107                 return (false);
108         }
109
110         if((netlinkDescriptor = netherNetlink->getDescriptor()) == -1)
111         {
112                 LOGE("Netlink subsystem did not return a valid descriptor, exiting");
113                 return (false);
114         }
115
116         /* Load the rules as last, in case we have a problem with any
117                 above subsystems, we won't leave hanging useless rules */
118         if(netherConfig.noRules == 0 && restoreRules() == false)
119         {
120                 LOGE("Failed to setup iptables rules");
121                 return (false);
122         }
123
124         if((backendDescriptor = netherPrimaryPolicyBackend->getDescriptor()) == -1)
125         {
126                 LOGI("Policy backend does not provide descriptor for select()");
127         }
128
129         return (true);
130 }
131
132 bool NetherManager::process()
133 {
134         fd_set watchedReadDescriptorsSet, watchedWriteDescriptorsSet;
135         struct timeval timeoutSpecification;
136
137         for(;;)
138         {
139                 setupSelectSockets(watchedReadDescriptorsSet, watchedWriteDescriptorsSet, timeoutSpecification);
140
141                 if(select(FD_SETSIZE, &watchedReadDescriptorsSet, &watchedWriteDescriptorsSet, NULL, &timeoutSpecification) < 0)
142                 {
143                         LOGE("select error " << strerror(errno));
144                         return (false);
145                 }
146
147                 if(FD_ISSET(signalDescriptor, &watchedReadDescriptorsSet))
148                 {
149                         handleSignal();
150                 }
151                 if(FD_ISSET(netlinkDescriptor, &watchedReadDescriptorsSet))
152                 {
153                         if(!handleNetlinkpacket())
154                                 break;
155                 }
156                 else
157                         if(FD_ISSET(backendDescriptor, &watchedReadDescriptorsSet) || FD_ISSET(backendDescriptor, &watchedWriteDescriptorsSet))
158                         {
159                                 netherPrimaryPolicyBackend->processEvents();
160                         }
161                         else
162                         {
163                                 LOGD("select() timeout");
164                         }
165         }
166
167         return (true);
168 }
169
170 void NetherManager::handleSignal()
171 {
172         LOGD("received signal");
173         ssize_t signalRead;
174         struct signalfd_siginfo signalfdSignalInfo;
175
176         signalRead = read(signalDescriptor, &signalfdSignalInfo, sizeof(struct signalfd_siginfo));
177
178         if(signalRead != sizeof(struct signalfd_siginfo))
179         {
180                 LOGW("Received incomplete signal information, ignore");
181                 return;
182         }
183
184         if(signalfdSignalInfo.ssi_signo == SIGHUP)
185         {
186                 LOGI("SIGHUP received, reloading");
187                 if(!netherPrimaryPolicyBackend->reload())
188                         LOGW("primary backend failed to reload");
189                 if(!netherBackupPolicyBackend->reload())
190                         LOGW("backup backend failed to reload");
191                 if(!netherNetlink->reload())
192                         LOGW("netlink failed to reload");
193         }
194 }
195
196 bool NetherManager::handleNetlinkpacket()
197 {
198         LOGD("netlink descriptor active");
199         int packetReadSize;
200         NetherPacket receivedPacket;
201         char packetBuffer[NETHER_PACKET_BUFFER_SIZE] __attribute__((aligned));
202
203         /* some data arrives on netlink, read it */
204         if((packetReadSize = recv(netlinkDescriptor, packetBuffer, sizeof(packetBuffer), 0)) >= 0)
205         {
206                 /* try to process the packet using netfilter_queue library, fetch packet info
207                     needed for making a decision about it */
208                 if(netherNetlink->processPacket(packetBuffer, packetReadSize))
209                 {
210                         return (true);
211                 }
212                 else
213                 {
214                         /* if we can't process the incoming packets, it's bad. Let's exit now */
215                         LOGE("Failed to process netlink received packet, refusing to continue");
216                         return (false);
217                 }
218         }
219
220         if(packetReadSize < 0 && errno == ENOBUFS)
221         {
222                 LOGI("NetherManager::process losing packets! [bad things might happen]");
223                 return (true);
224         }
225
226         LOGE("NetherManager::process recv failed " << strerror(errno));
227         return (false);
228 }
229
230 void NetherManager::setupSelectSockets(fd_set &watchedReadDescriptorsSet, fd_set &watchedWriteDescriptorsSet, struct timeval &timeoutSpecification)
231 {
232         FD_ZERO(&watchedReadDescriptorsSet);
233         FD_ZERO(&watchedWriteDescriptorsSet);
234
235         /* Always listen for signals */
236         FD_SET(signalDescriptor, &watchedReadDescriptorsSet);
237
238         if((netlinkDescriptor = netherNetlink->getDescriptor()) >= 0)
239         {
240                 FD_SET(netlinkDescriptor, &watchedReadDescriptorsSet);
241         }
242
243         if((backendDescriptor = netherPrimaryPolicyBackend->getDescriptor()) >= 0)
244         {
245                 if(netherPrimaryPolicyBackend->getDescriptorStatus() == NetherDescriptorStatus::readOnly)
246                 {
247                         FD_SET(backendDescriptor, &watchedReadDescriptorsSet);
248                 }
249                 else
250                         if(netherPrimaryPolicyBackend->getDescriptorStatus() == NetherDescriptorStatus::readWrite)
251                         {
252                                 FD_SET(backendDescriptor, &watchedReadDescriptorsSet);
253                                 FD_SET(backendDescriptor, &watchedWriteDescriptorsSet);
254                         }
255         }
256
257         timeoutSpecification.tv_sec     = 240;
258         timeoutSpecification.tv_usec    = 0;
259 }
260
261 NetherConfig &NetherManager::getConfig()
262 {
263         return (netherConfig);
264 }
265
266 NetherPolicyBackend *NetherManager::getPolicyBackend(const NetherConfig &netherConfig, const bool primary)
267 {
268         switch(primary ? netherConfig.primaryBackendType : netherConfig.backupBackendType)
269         {
270                 case NetherPolicyBackendType::cynaraBackend:
271 #ifdef HAVE_CYNARA
272                         return new NetherCynaraBackend(netherConfig);
273 #else
274                         return new NetherDummyBackend(netherConfig);
275 #endif
276                 case NetherPolicyBackendType::fileBackend:
277                         return new NetherFileBackend(netherConfig);
278                 case NetherPolicyBackendType::dummyBackend:
279                 default:
280                         return new NetherDummyBackend(netherConfig);
281         }
282 }
283
284 bool NetherManager::verdictCast(const u_int32_t packetId, const NetherVerdict verdict, int mark)
285 {
286         if(netherNetlink)
287         {
288                 netherNetlink->setVerdict(packetId, verdict, mark);
289         }
290         else
291         {
292                 LOGE("Netlink subsystem is invalid, can't decide on packet");
293                 return (false);
294         }
295
296         return (true);
297 }
298
299 void NetherManager::packetReceived(const NetherPacket &packet)
300 {
301         LOGD(packetToString(packet).c_str());
302
303         if(netherPrimaryPolicyBackend && netherPrimaryPolicyBackend->enqueueVerdict(packet))
304         {
305                 LOGD("Primary policy accepted packet");
306                 return;
307         }
308
309         if(netherBackupPolicyBackend && netherBackupPolicyBackend->enqueueVerdict(packet))
310         {
311                 LOGI("Primary policy backend failed, using backup policy backend");
312                 return;
313         }
314
315         /* In this situation no policy backend wants to deal with this packet
316             there propably isn't any rule in either of them
317
318             we need to make a generic decision based on whatever is hard-coded
319             or passed as a parameter to the service */
320         LOGW("All policy backends failed, using DUMMY backend");
321         netherFallbackPolicyBackend->enqueueVerdict(packet);
322 }
323
324 bool NetherManager::restoreRules()
325 {
326         if(!isCommandAvailable(netherConfig.iptablesRestorePath))
327         {
328                 return (false);
329         }
330
331         std::stringstream cmdline;
332         cmdline << netherConfig.iptablesRestorePath;
333         cmdline << " ";
334         cmdline << netherConfig.rulesPath;
335
336         if(system(cmdline.str().c_str()))
337         {
338                 LOGE("system() failed for: " << cmdline.str());
339                 return (false);
340         }
341
342         LOGD("iptables-restore succeeded with rules from: " << netherConfig.rulesPath);
343         return (true);
344 }
345
346 bool NetherManager::isCommandAvailable(const std::string &command)
347 {
348         struct stat iptablesRestoreStat;
349
350         if(stat(command.c_str(), &iptablesRestoreStat) == 0)
351         {
352                 if(! iptablesRestoreStat.st_mode & S_IXUSR)
353                 {
354                         LOGE("Execute bit is not set for owner on:" << command);
355                         return (false);
356                 }
357
358                 return (true);
359         }
360
361         LOGE("Failed to stat command at: " << command << " error: " << strerror(errno));
362         return (false);
363 }