Tizen 2.1 base
[framework/security/security-server.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 <errno.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/signalfd.h>
27 #include <sys/select.h>
28 #include <sys/stat.h>
29 #include <signal.h>
30 #include <fcntl.h>
31 #include <cstring>
32 #include <dpl/log/log.h>
33 #include "ace_service_callbacks_api.h"
34 #include "ocsp_service_callbacks_api.h"
35 #include "popup_service_callbacks_api.h"
36 #include "security_daemon_socket_config.h"
37 #include "security_socket_service.h"
38
39 #define TIMEOUT_SEC 0
40 #define TIMEOUT_NSEC 100000000
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 void SecuritySocketService::initialize(){
86
87     LogInfo("Initializing...");
88     m_serverAddress = WrtSecurity::SecurityDaemonSocketConfig::SERVER_ADDRESS();
89     m_signalToClose = SIGNAL_TO_CLOSE;
90
91     //registering Ace callbacks
92     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
93                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().first,
94                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().second);
95
96     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
97                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_INSTALL_METHOD_CALLBACK().first,
98                             WrtSecurity::AceServiceCallbacksApi::CHECK_ACCESS_INSTALL_METHOD_CALLBACK().second);
99
100     registerServiceCallback(WrtSecurity::AceServerApi::INTERFACE_NAME(),
101                             WrtSecurity::AceServiceCallbacksApi::UPDATE_POLICY_METHOD_CALLBACK().first,
102                             WrtSecurity::AceServiceCallbacksApi::UPDATE_POLICY_METHOD_CALLBACK().second);
103     LogInfo("Registered Ace callbacks");
104
105     //registering Ocsp callbacks
106     registerServiceCallback(WrtSecurity::OcspServerApi::INTERFACE_NAME(),
107                             WrtSecurity::OcspServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().first,
108                             WrtSecurity::OcspServiceCallbacksApi::CHECK_ACCESS_METHOD_CALLBACK().second);
109     LogInfo("Registered Ocsp callbacks");
110
111     //registering Popup callbacks
112     registerServiceCallback(WrtSecurity::PopupServerApi::INTERFACE_NAME(),
113                             WrtSecurity::PopupServiceCallbacksApi::VALIDATION_METHOD_CALLBACK().first,
114                             WrtSecurity::PopupServiceCallbacksApi::VALIDATION_METHOD_CALLBACK().second);
115     LogInfo("Registered Popup callbacks");
116
117     if(-1 == (m_listenFd = socket(AF_UNIX, SOCK_STREAM, 0))){
118         throwWithErrnoMessage("socket()");
119     }
120     LogInfo("Server socket created");
121
122     //socket needs to be nonblocking, because read can block after select
123     int flags;
124     if (-1 == (flags = fcntl(m_listenFd, F_GETFL, 0)))
125         flags = 0;
126     if(-1 == (fcntl(m_listenFd, F_SETFL, flags | O_NONBLOCK))){
127         throwWithErrnoMessage("fcntl");
128     }
129
130     sockaddr_un server_address;
131     bzero(&server_address, sizeof(server_address));
132     server_address.sun_family = AF_UNIX;
133     strcpy(server_address.sun_path, m_serverAddress.c_str());
134     unlink(server_address.sun_path);
135
136     mode_t socket_umask, original_umask;
137     socket_umask = 0;
138     original_umask = umask(socket_umask);
139
140     if(-1 == bind(m_listenFd, (struct sockaddr *)&server_address, SUN_LEN(&server_address))){
141         throwWithErrnoMessage("bind()");
142     }
143
144     umask(original_umask);
145
146     LogInfo("Initialized");
147 }
148
149 void SecuritySocketService::start(){
150
151     LogInfo("Starting...");
152     if(m_serverAddress.empty()){
153         LogError("Server not initialized");
154         ThrowMsg(DPL::Exception, "Server not initialized");
155     }
156
157     sigset_t sigset;
158     sigemptyset(&sigset);
159     if(-1 == sigaddset(&sigset, m_signalToClose)){
160         throwWithErrnoMessage("sigaddset()");
161     }
162     int returned_value;
163     if ((returned_value = pthread_sigmask(SIG_BLOCK, &sigset, NULL)) < 0) {
164         errno = returned_value;
165         throwWithErrnoMessage("pthread_sigmask()");
166     }
167
168     pthread_t mainThread;
169
170     if((returned_value = pthread_create(&mainThread, NULL, &serverThread, this)) < 0){
171         errno = returned_value;
172         throwWithErrnoMessage("pthread_create()");
173     }
174     m_mainThread = mainThread;
175
176     LogInfo("Started");
177 }
178
179 void * SecuritySocketService::serverThread(void * data){
180     pthread_detach(pthread_self());
181     SecuritySocketService &t = *static_cast<SecuritySocketService *>(data);
182     LogInfo("Running server main thread");
183     Try {
184         t.mainLoop();
185     } Catch (DPL::Exception) {
186         LogError("Socket server error. Exiting...");
187         return (void *)1;
188     }
189
190     return (void *)0;
191 }
192
193
194 void SecuritySocketService::mainLoop(){
195
196     if(listen(m_listenFd, MAX_LISTEN) == -1){
197         throwWithErrnoMessage("listen()");
198     }
199
200     //Settings to catch closing signal in select
201     int signal_fd;
202     sigset_t sigset;
203     if(-1 == (sigemptyset(&sigset))){
204         throwWithErrnoMessage("sigemptyset()");
205     }
206     if(-1 == (sigaddset(&sigset, m_signalToClose))) {
207         throwWithErrnoMessage("sigaddset()");
208     }
209     if((signal_fd = signalfd(-1, &sigset, 0)) < 0){
210         throwWithErrnoMessage("signalfd()");
211     }
212
213     //Setting descriptors for pselect
214     fd_set allset, rset;
215     int maxfd;
216     FD_ZERO(&allset);
217     FD_SET(m_listenFd, &allset);
218     FD_SET(signal_fd, &allset);
219     timespec timeout;
220     maxfd = (m_listenFd > signal_fd) ? (m_listenFd) : (signal_fd);
221     ++maxfd;
222     //this will block SIGPIPE for this thread and every thread created in it
223     //reason : from here on we don't won't to receive SIGPIPE on writing to closed socket
224     //instead of signal we want to receive error from write - hence blocking SIGPIPE
225     sigset_t set;
226     sigemptyset(&set);
227     sigaddset(&set, SIGPIPE);
228     pthread_sigmask(SIG_BLOCK, &set, NULL);
229
230     while(1){
231         timeout.tv_sec = TIMEOUT_SEC;
232         timeout.tv_nsec = TIMEOUT_NSEC;
233         rset = allset;
234         if(-1 == pselect(maxfd, &rset, NULL, NULL, &timeout, NULL)){
235             closeConnections();
236             throwWithErrnoMessage("pselect()");
237         }
238
239         if(FD_ISSET(signal_fd, &rset)){
240             LogInfo("Got signal to close");
241             signalfd_siginfo siginfo;
242             ssize_t res;
243             res = read(signal_fd, &siginfo, sizeof(siginfo));
244             if(res <= 0){
245                 closeConnections();
246                 throwWithErrnoMessage("read()");
247             }
248             if((size_t)res != sizeof(siginfo)){
249                 closeConnections();
250                 LogError("couldn't read whole siginfo");
251                 ThrowMsg(DPL::Exception, "couldn't read whole siginfo");
252             }
253             if((int)siginfo.ssi_signo == m_signalToClose){
254                 LogInfo("Server thread got signal to close");
255                 closeConnections();
256                 return;
257             } else {
258                 LogInfo("Got not handled signal");
259             }
260         }
261         if(FD_ISSET(m_listenFd, &rset)){
262             int client_fd;
263             if(-1 == (client_fd = accept(m_listenFd, NULL, NULL))){
264                 closeConnections();
265                 throwWithErrnoMessage("accept()");
266             }
267             LogInfo("Got incoming connection");
268             Connection_Info * connection = new Connection_Info(client_fd, (void *)this);
269             int res;
270             pthread_t client_thread;
271             if((res = pthread_create(&client_thread, NULL, &connectionThread, connection)) < 0){
272                 delete connection;
273                 errno = res;
274                 closeConnections();
275                 throwWithErrnoMessage("pthread_create()");
276             }
277             addClientSocket(client_fd);
278         }
279     }
280 }
281
282 void * SecuritySocketService::connectionThread(void * data){
283     pthread_detach(pthread_self());
284     std::auto_ptr<Connection_Info> c (static_cast<Connection_Info *>(data));
285     SecuritySocketService &t = *static_cast<SecuritySocketService *>(c->data);
286     LogInfo("Starting connection thread");
287     Try {
288         t.connectionService(c->connfd);
289     } Catch (DPL::Exception){
290         LogError("Connection thread error : " << _rethrown_exception.DumpToString());
291         t.removeClientSocket(c->connfd);
292         close(c->connfd);
293         return (void*)1;
294     }
295     LogInfo("Client serviced");
296     return (void*)0;
297 }
298
299 void SecuritySocketService::connectionService(int fd){
300
301     SocketConnection connector = SocketConnection(fd);
302     std::string interfaceName, methodName;
303
304     Try {
305         connector.read(&interfaceName, &methodName);
306     } Catch (SocketConnection::Exception::SocketConnectionException){
307         LogError("Socket Connection read error");
308         ReThrowMsg(DPL::Exception, "Socket Connection read error");
309     }
310
311     LogDebug("Got interface : " << interfaceName);
312     LogDebug("Got method : " << methodName);
313
314     if( m_callbackMap.find(interfaceName) == m_callbackMap.end()){
315         LogError("Unknown interface : " << interfaceName);
316         ThrowMsg(DPL::Exception, "Unknown interface : " << interfaceName);
317     }
318
319     if(m_callbackMap[interfaceName].find(methodName) == m_callbackMap[interfaceName].end()){
320         LogError("Unknown method : " << methodName);
321         ThrowMsg(DPL::Exception, "Unknown method");
322     }
323
324     if(m_callbackMap[interfaceName][methodName]->securityCallback != NULL){
325         if(!m_callbackMap[interfaceName][methodName]->securityCallback(fd)){
326             LogError("Security check returned false");
327             ThrowMsg(DPL::Exception, "Security check returned false");
328         }
329     }
330
331     LogInfo("Calling service");
332     Try{
333         m_callbackMap[interfaceName][methodName]->serviceCallback(&connector);
334     } Catch (ServiceCallbackApi::Exception::ServiceCallbackException){
335         LogError("Service callback error");
336         ReThrowMsg(DPL::Exception, "Service callback error");
337     }
338
339     LogInfo("Removing client");
340     removeClientSocket(fd);
341     close(fd);
342
343     LogInfo("Call served");
344
345 }
346
347 void SecuritySocketService::stop(){
348     LogInfo("Stopping");
349     if(-1 == close(m_listenFd))
350         if(errno != ENOTCONN)
351             throwWithErrnoMessage("close()");
352     int returned_value;
353     if((returned_value = pthread_kill(m_mainThread, m_signalToClose)) < 0){
354         errno = returned_value;
355         throwWithErrnoMessage("pthread_kill()");
356     }
357     pthread_join(m_mainThread, NULL);
358
359     LogInfo("Stopped");
360 }
361
362 void SecuritySocketService::closeConnections(){
363
364     int clientSocket;
365     LogInfo("Closing client sockets");
366     while(popClientSocket(&clientSocket)){
367         if(-1 == close(clientSocket)){
368             LogError("close() : " << strerror(errno));
369         }
370     }
371
372     LogInfo("Connections closed");
373 }
374
375 void SecuritySocketService::deinitialize(){
376     m_serverAddress.clear();
377
378     LogInfo("Deinitialized");
379
380 }
381
382 #ifdef SOCKET_CONNECTION
383 DAEMON_REGISTER_SERVICE_MODULE(SecuritySocketService)
384 #endif