wrt-security - add systemd support
[platform/framework/web/wrt-security.git] / src / daemon / sockets / security_socket_service.cpp
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file        security_socket_service.cpp
18  * @author      Zofia Abramowska (z.abramowska@samsung.com)
19  * @version     1.0
20  * @brief       Implementation of socket server
21  */
22 #include <systemd/sd-daemon.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/signalfd.h>
28 #include <sys/select.h>
29 #include <sys/stat.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <cstring>
33 #include <unistd.h>
34 #include <dpl/log/log.h>
35 #include "ace_service_callbacks_api.h"
36 #include "ocsp_service_callbacks_api.h"
37 #include "popup_service_callbacks_api.h"
38 #include "security_daemon_socket_config.h"
39 #include "security_socket_service.h"
40
41 #define MAX_LISTEN 5
42 #define SIGNAL_TO_CLOSE SIGUSR1
43
44 void SecuritySocketService::throwWithErrnoMessage(const std::string& specificInfo){
45     LogError(specificInfo << " : " << strerror(errno));
46     ThrowMsg(DPL::Exception, specificInfo << " : " << strerror(errno));
47 }
48
49 void SecuritySocketService::registerServiceCallback(const std::string &interfaceName,
50                                                     const std::string &methodName,
51                                                     socketServerCallback callbackMethod,
52                                                     securityCheck securityMethod){
53     if(NULL == callbackMethod){
54         LogError("Null callback");
55         ThrowMsg(DPL::Exception, "Null callback");
56     }
57     if(interfaceName.empty() || methodName.empty()){
58         LogError("Interface and method name cannot be empty");
59         ThrowMsg(DPL::Exception, "Empty interface or method name");
60     }
61
62     auto serviceCallbackPtr = std::make_shared<ServiceCallback>(ServiceCallback(callbackMethod, securityMethod));
63     m_callbackMap[interfaceName][methodName] = serviceCallbackPtr;
64 }
65
66 void SecuritySocketService::addClientSocket(int clientSocket){
67     std::lock_guard<std::mutex> guard(m_clientSocketListMutex);
68     m_clientSocketList.push_back(clientSocket);
69 }
70
71 void SecuritySocketService::removeClientSocket(int clientSocket){
72     std::lock_guard<std::mutex> guard(m_clientSocketListMutex);
73     m_clientSocketList.remove(clientSocket);
74 }
75
76 bool SecuritySocketService::popClientSocket(int * clientSocket){
77     std::lock_guard<std::mutex> guard(m_clientSocketListMutex);
78     if(m_clientSocketList.empty())
79         return false;
80     *clientSocket = m_clientSocketList.front();
81     m_clientSocketList.pop_front();
82     return true;
83 }
84
85 int SecuritySocketService::get_systemd_socket(std::string &path) {
86
87         int type = SOCK_STREAM;
88         int listening = 1;
89         size_t length = 0;
90         int fd = -1;
91         int n;
92
93         // Gets number of created by systemd file descriptors that represent open sockets.
94         n = sd_listen_fds(1);
95
96         // Check open sockets count (must be 1)
97         if (n != 1)
98                 return -1;
99
100         // File descriptor calculation
101         fd = SD_LISTEN_FDS_START  + 0;
102
103         // File descriptor veryfication.
104         if (sd_is_socket_unix(fd, type, listening, path.c_str(), length) > 0) {
105                 activatedBySystemd = true;
106                 return fd;
107         }
108
109         // No proper socket or error
110         return -1;
111 }
112
113 void SecuritySocketService::initialize(){
114
115     LogInfo("Initializing...");
116     m_serverAddress = WrtSecurity::SecurityDaemonSocketConfig::SERVER_ADDRESS();
117     m_signalToClose = SIGNAL_TO_CLOSE;
118
119     //registering Ace callbacks
120     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
121                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().first,
122                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().second);
123
124     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
125                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_INSTALL_METHOD_CALLBACK().first,
126                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_INSTALL_METHOD_CALLBACK().second);
127
128     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
129                             WrtSecurity::AceServiceCallbacksApi::UPDATE_POLICY_METHOD_CALLBACK().first,
130                             WrtSecurity::AceServiceCallbacksApi::UPDATE_POLICY_METHOD_CALLBACK().second);
131     LogInfo("Registered Ace callbacks");
132
133     //registering Ocsp callbacks
134     registerServiceCallback(WrtSecurity::OcspServerApi::INTERFACE_NAME(),
135                             WrtSecurity::OcspServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().first,
136                             WrtSecurity::OcspServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().second);
137     LogInfo("Registered Ocsp callbacks");
138
139     //registering Popup callbacks
140     registerServiceCallback(WrtSecurity::PopupServerApi::INTERFACE_NAME(),
141                             WrtSecurity::PopupServiceCallbacksApi::VALIDATION_METHOD_CALLBACK().first,
142                             WrtSecurity::PopupServiceCallbacksApi::VALIDATION_METHOD_CALLBACK().second);
143     LogInfo("Registered Popup callbacks");
144
145     // Get systemd socket
146     activatedBySystemd = false;
147     m_listenFd = get_systemd_socket(m_serverAddress);
148     if (m_listenFd >= 0) {
149         LogInfo("Initialized");
150         return;
151     }
152
153     // Default socket initialization
154     if(-1 == (m_listenFd = socket(AF_UNIX, SOCK_STREAM, 0))){
155         throwWithErrnoMessage("socket()");
156     }
157     LogInfo("Server socket created");
158
159     //socket needs to be nonblocking, because read can block after select
160     int flags;
161     if (-1 == (flags = fcntl(m_listenFd, F_GETFL, 0)))
162         flags = 0;
163     if(-1 == (fcntl(m_listenFd, F_SETFL, flags | O_NONBLOCK))){
164         throwWithErrnoMessage("fcntl");
165     }
166
167     sockaddr_un server_address;
168     bzero(&server_address, sizeof(server_address));
169     server_address.sun_family = AF_UNIX;
170     strcpy(server_address.sun_path, m_serverAddress.c_str());
171     unlink(server_address.sun_path);
172
173     mode_t socket_umask, original_umask;
174     socket_umask = 0;
175     original_umask = umask(socket_umask);
176
177     if(-1 == bind(m_listenFd, (struct sockaddr *)&server_address, SUN_LEN(&server_address))){
178         throwWithErrnoMessage("bind()");
179     }
180
181     umask(original_umask);
182
183     LogInfo("Initialized");
184 }
185
186 void SecuritySocketService::start(){
187
188     LogInfo("Starting...");
189     if(m_serverAddress.empty()){
190         LogError("Server not initialized");
191         ThrowMsg(DPL::Exception, "Server not initialized");
192     }
193
194     sigset_t sigset;
195     sigemptyset(&sigset);
196     if(-1 == sigaddset(&sigset, m_signalToClose)){
197         throwWithErrnoMessage("sigaddset()");
198     }
199     int returned_value;
200     if ((returned_value = pthread_sigmask(SIG_BLOCK, &sigset, NULL)) < 0) {
201         errno = returned_value;
202         throwWithErrnoMessage("pthread_sigmask()");
203     }
204
205     pthread_t mainThread;
206     if((returned_value = pthread_create(&mainThread, NULL, &serverThread, this)) < 0){
207         errno = returned_value;
208         throwWithErrnoMessage("pthread_create()");
209     }
210     m_mainThread = mainThread;
211
212     LogInfo("Started");
213 }
214
215 void * SecuritySocketService::serverThread(void * data){
216     pthread_detach(pthread_self());
217     SecuritySocketService &t = *static_cast<SecuritySocketService *>(data);
218     LogInfo("Running server main thread");
219     Try {
220         t.mainLoop();
221     } Catch (DPL::Exception) {
222         LogError("Socket server error. Exiting...");
223         return (void *)1;
224     }
225
226     return (void *)0;
227 }
228
229
230 void SecuritySocketService::mainLoop(){
231
232     if(!activatedBySystemd && listen(m_listenFd, MAX_LISTEN) == -1){
233         throwWithErrnoMessage("listen()");
234     }
235
236     //Settings to catch closing signal in select
237     int signal_fd;
238     sigset_t sigset;
239     if(-1 == (sigemptyset(&sigset))){
240         throwWithErrnoMessage("sigemptyset()");
241     }
242     if(-1 == (sigaddset(&sigset, m_signalToClose))) {
243         throwWithErrnoMessage("sigaddset()");
244     }
245     if((signal_fd = signalfd(-1, &sigset, 0)) < 0){
246         throwWithErrnoMessage("signalfd()");
247     }
248
249     //Setting descriptors for pselect
250     fd_set allset, rset;
251     int maxfd;
252     FD_ZERO(&allset);
253     FD_SET(m_listenFd, &allset);
254     FD_SET(signal_fd, &allset);
255     maxfd = (m_listenFd > signal_fd) ? (m_listenFd) : (signal_fd);
256     ++maxfd;
257     //this will block SIGPIPE for this thread and every thread created in it
258     //reason : from here on we don't won't to receive SIGPIPE on writing to closed socket
259     //instead of signal we want to receive error from write - hence blocking SIGPIPE
260     sigset_t set;
261     sigemptyset(&set);
262     sigaddset(&set, SIGPIPE);
263     pthread_sigmask(SIG_BLOCK, &set, NULL);
264
265     while(1){
266         rset = allset;
267         if(-1 == pselect(maxfd, &rset, NULL, NULL, NULL, NULL)){
268             closeConnections();
269             throwWithErrnoMessage("pselect()");
270         }
271
272         if(FD_ISSET(signal_fd, &rset)){
273             LogInfo("Got signal to close");
274             signalfd_siginfo siginfo;
275             ssize_t res;
276             res = read(signal_fd, &siginfo, sizeof(siginfo));
277             if(res <= 0){
278                 closeConnections();
279                 throwWithErrnoMessage("read()");
280             }
281             if((size_t)res != sizeof(siginfo)){
282                 closeConnections();
283                 LogError("couldn't read whole siginfo");
284                 ThrowMsg(DPL::Exception, "couldn't read whole siginfo");
285             }
286             if((int)siginfo.ssi_signo == m_signalToClose){
287                 LogInfo("Server thread got signal to close");
288                 closeConnections();
289                 return;
290             } else {
291                 LogInfo("Got not handled signal");
292             }
293         }
294         if(FD_ISSET(m_listenFd, &rset)){
295             int client_fd;
296             if(-1 == (client_fd = accept(m_listenFd, NULL, NULL))){
297                 closeConnections();
298                 throwWithErrnoMessage("accept()");
299             }
300             LogInfo("Got incoming connection");
301             Connection_Info * connection = new Connection_Info(client_fd, (void *)this);
302             int res;
303             pthread_t client_thread;
304             if((res = pthread_create(&client_thread, NULL, &connectionThread, connection)) < 0){
305                 delete connection;
306                 errno = res;
307                 closeConnections();
308                 throwWithErrnoMessage("pthread_create()");
309             }
310             addClientSocket(client_fd);
311         }
312     }
313 }
314
315 void * SecuritySocketService::connectionThread(void * data){
316     pthread_detach(pthread_self());
317     std::auto_ptr<Connection_Info> c (static_cast<Connection_Info *>(data));
318     SecuritySocketService &t = *static_cast<SecuritySocketService *>(c->data);
319     LogInfo("Starting connection thread");
320     Try {
321         t.connectionService(c->connfd);
322     } Catch (DPL::Exception){
323         LogError("Connection thread error : " << _rethrown_exception.DumpToString());
324         t.removeClientSocket(c->connfd);
325         close(c->connfd);
326         return (void*)1;
327     }
328     LogInfo("Client serviced");
329     return (void*)0;
330 }
331
332 void SecuritySocketService::connectionService(int fd){
333
334     SocketConnection connector = SocketConnection(fd);
335     std::string interfaceName, methodName;
336
337     Try {
338         connector.read(&interfaceName, &methodName);
339     } Catch (SocketConnection::Exception::SocketConnectionException){
340         LogError("Socket Connection read error");
341         ReThrowMsg(DPL::Exception, "Socket Connection read error");
342     }
343
344     LogDebug("Got interface : " << interfaceName);
345     LogDebug("Got method : " << methodName);
346
347     if( m_callbackMap.find(interfaceName) == m_callbackMap.end()){
348         LogError("Unknown interface : " << interfaceName);
349         ThrowMsg(DPL::Exception, "Unknown interface : " << interfaceName);
350     }
351
352     if(m_callbackMap[interfaceName].find(methodName) == m_callbackMap[interfaceName].end()){
353         LogError("Unknown method : " << methodName);
354         ThrowMsg(DPL::Exception, "Unknown method");
355     }
356
357     if(m_callbackMap[interfaceName][methodName]->securityCallback != NULL){
358         if(!m_callbackMap[interfaceName][methodName]->securityCallback(fd)){
359             LogError("Security check returned false");
360             ThrowMsg(DPL::Exception, "Security check returned false");
361         }
362     }
363
364     LogInfo("Calling service");
365     Try{
366         m_callbackMap[interfaceName][methodName]->serviceCallback(&connector);
367     } Catch (ServiceCallbackApi::Exception::ServiceCallbackException){
368         LogError("Service callback error");
369         ReThrowMsg(DPL::Exception, "Service callback error");
370     }
371
372     LogInfo("Removing client");
373     removeClientSocket(fd);
374     close(fd);
375
376     LogInfo("Call served");
377
378 }
379
380 void SecuritySocketService::stop(){
381     LogInfo("Stopping");
382     if(-1 == close(m_listenFd))
383         if(errno != ENOTCONN)
384             throwWithErrnoMessage("close()");
385     int returned_value;
386     if((returned_value = pthread_kill(m_mainThread, m_signalToClose)) < 0){
387         errno = returned_value;
388         throwWithErrnoMessage("pthread_kill()");
389     }
390     pthread_join(m_mainThread, NULL);
391
392     LogInfo("Stopped");
393 }
394
395 void SecuritySocketService::closeConnections(){
396
397     int clientSocket;
398     LogInfo("Closing client sockets");
399     while(popClientSocket(&clientSocket)){
400         if(-1 == close(clientSocket)){
401             LogError("close() : " << strerror(errno));
402         }
403     }
404
405     LogInfo("Connections closed");
406 }
407
408 void SecuritySocketService::deinitialize(){
409     m_serverAddress.clear();
410
411     LogInfo("Deinitialized");
412
413 }
414
415 #ifdef SOCKET_CONNECTION
416 DAEMON_REGISTER_SERVICE_MODULE(SecuritySocketService)
417 #endif