Add caching of App/Pkg data & use faster way to retrieve this data
[platform/core/security/askuser.git] / src / notification-daemon / Logic.cpp
1 /*
2  *  Copyright (c) 2017-2018 Samsung Electronics Co.
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        Logic.cpp
18  * @author      Zofia Grzelewska <z.abramowska@samsung.com>
19  * @brief       Declaration of Logic class
20  */
21
22 #include "Logic.h"
23
24 #include <algorithm>
25 #include <signal.h>
26 #include <string>
27 #include <sys/signalfd.h>
28 #include <vconf.h>
29 #include <Elementary.h>
30
31 #include <exception/Exception.h>
32 #include <exception/ErrnoException.h>
33 #include <policy/Policy.h>
34 #include <policy/PrivilegePolicy.h>
35
36 #include "PolicyUpdater.h"
37 #include "ServerCallbacks.h"
38
39 namespace AskUser {
40
41 namespace Notification {
42
43 namespace {
44
45 int ASKUSER_IDLE_TIMER_SEC = 4;
46
47 int uiResponseToClientResponse(NResponseType response) {
48     int clientResponse;
49
50     switch (response) {
51     case NResponseType::Deny:
52         clientResponse = ASKUSER_DENY_ONCE;
53         break;
54     case NResponseType::DenyAlways:
55         clientResponse = ASKUSER_DENY_FOREVER;
56         break;
57     case NResponseType::Allow:
58     case NResponseType::AllowAlways:
59         clientResponse = ASKUSER_ALLOW_FOREVER;
60         break;
61     case NResponseType::None:
62         clientResponse = ASKUSER_NONE;
63         break;
64     case NResponseType::Error:
65         clientResponse = ASKUSER_UNKNOWN_ERROR;
66         break;
67     default:
68         clientResponse = ASKUSER_UNKNOWN_ERROR;
69     }
70
71     return clientResponse;
72 }
73
74 std::string clientResponseToPolicy(int clientResponse) {
75     std::string level;
76
77     switch (clientResponse) {
78     case ASKUSER_DENY_FOREVER:
79         level = "Deny";
80         break;
81     case ASKUSER_ALLOW_FOREVER:
82         level = "Allow";
83         break;
84     default :
85         level = "Ask user";
86     }
87
88     return level;
89 }
90
91 }
92
93 void Logic::addChannelFd(Protocol::ConnectionFd fd, const Protocol::Credentials &creds) {
94     try {
95         ALOGD("Adding new client with fd " << fd);
96         auto it = m_connToInfo.find(fd);
97         if (it != m_connToInfo.end()) {
98             ALOGE("Connection with fd : " << fd << " already exists. Closing connection");
99             m_serverChannel->process(fd, 0);
100             return;
101         }
102
103         if (creds.uid != std::to_string(geteuid())) {
104             ALOGE("This is very unexpected, client with different uid connected : " << creds.uid);
105             m_serverChannel->process(fd, 0);
106         }
107
108         std::string appId, pkgLabel;
109         PkgMgrPkgInfo pkgInfo;
110         identifyApp(pkgInfo, creds.label, appId, pkgLabel);
111
112         ALOGD("Proper client connected");
113         stopTimer();
114
115         ConnectionInfo connInfo{appId, pkgLabel, creds.uid};
116         m_connToInfo.insert(it, std::make_pair(fd, connInfo));
117     } catch (const std::exception &e) {
118         ALOGE("Failed to add channel fd " << fd);
119     }
120 }
121
122 void Logic::updateChannelFd(Protocol::ConnectionFd fd, Ecore_Fd_Handler_Flags flags) {
123     ALOGD("Updating channel with fd " << fd << " and flags " << flags);
124     auto it = m_fdInfo.find(fd);
125     if (it != m_fdInfo.end()) {
126         m_fdInfo[fd].status = FdChange::CHANGE;
127         ecore_main_fd_handler_del(m_fdInfo[fd].handler);
128     } else {
129         m_fdInfo[fd].status = FdChange::NONE;
130     }
131
132     auto handler = ecore_main_fd_handler_add(fd, flags, &Logic::clientChHandler, this, nullptr, nullptr);
133     if (handler == nullptr) {
134         ALOGE("Couldn't set fd handler");
135         m_fdInfo[fd].status = FdChange::DEL;
136         return;
137     }
138     m_fdInfo[fd].handler = handler;
139 }
140
141 void Logic::removeChannelFd(Protocol::ConnectionFd fd) {
142     ALOGD("Removing channel with fd " << fd);
143     m_connToInfo.erase(fd);
144
145     if (m_connToInfo.empty()) {
146         ALOGD("No more clients");
147         startTimer();
148     }
149     auto it = m_fdInfo.find(fd);
150     if (it == m_fdInfo.end()) {
151         return;
152     }
153     it->second.status = FdChange::DEL;
154     ecore_main_fd_handler_del(it->second.handler);
155 }
156
157 Eina_Bool Logic::clientChHandler(void *data, Ecore_Fd_Handler *handler) {
158     Logic *service = static_cast<Logic *>(data);
159     int fd = ecore_main_fd_handler_fd_get(handler);
160     if (fd == -1) {
161         ALOGE("Failed to fetch fd from handler");
162         return ECORE_CALLBACK_CANCEL;
163     }
164     int mask = 0;
165     if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
166         mask = AskUser::Protocol::READ;
167     } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) {
168         mask = AskUser::Protocol::WRITE;
169     }
170     return service->processChannel(fd, mask);
171 }
172
173 Eina_Bool Logic::processChannel(int fd, int mask) {
174     ALOGD("Porcesing fd " << fd << " with mask " << mask);
175     updateChannel(fd, mask);
176
177     switch (m_fdInfo[fd].status) {
178     case FdChange::NONE:
179         ALOGD("Fd is mark for renewal");
180         return ECORE_CALLBACK_RENEW;
181     case FdChange::DEL: {
182         ALOGD("Fd is marked for deletion");
183         // Remove all pending events from this fd
184         auto queueIt = std::remove_if(m_pendingEvents.begin(), m_pendingEvents.end(),
185                 [fd](const FdEvent &fdEvent) {return fdEvent.id.fd == fd;});
186         m_pendingEvents.erase(queueIt, m_pendingEvents.end());
187
188         // Ignore error in policy setting, we can't do anything about it nor we can inform user about error
189         (void)setPolicy(m_connToInfo[fd], "Ask user");
190         m_connToInfo.erase(fd);
191         m_fdInfo.erase(fd);
192         m_serverChannel->process(fd, 0);
193
194         // Handle next event if removed active fd
195         if (fd == m_currentEvent.fd) {
196             finishCurrentRequest();
197             processEvents();
198         }
199         return ECORE_CALLBACK_CANCEL;
200     }
201     case FdChange::CHANGE:
202         return ECORE_CALLBACK_CANCEL;
203     default:
204         ALOGE("Unexpected fd change value : " << static_cast<int>(m_fdInfo[fd].status));
205         return ECORE_CALLBACK_CANCEL;
206     }
207 }
208
209 void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::vector<Privacy> &privacies) {
210     EventId eventId{fd, id};
211     PrivaciesSequence &seq = m_eventToPrivaciesSeq[eventId];
212     seq.setPrivacies(privacies);
213
214     ConnectionInfo &conn = m_connToInfo[fd];
215
216     Privacy currentPrivacy;
217     seq.getNextPrivacy(currentPrivacy);
218
219     FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgLabel, currentPrivacy))};
220     m_pendingEvents.emplace_back(std::move(fdEvent));
221 }
222
223 void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::string &privilege) {
224     try {
225         ALOGD("Request for privilege " << privilege << " from fd " << fd << " with id " << id);
226
227         auto it = m_connToInfo.find(fd);
228         if (it == m_connToInfo.end()) {
229             ALOGE("Got request to non existing fd " << fd);
230             return;
231         }
232         ConnectionInfo &conn = it->second;
233
234         PrivilegePolicy privPolicy(conn.appId, privilege);
235         PkgMgrAppInfo appInfo;
236         auto policyLevel = privPolicy.calculatePolicy(appInfo);
237
238         ALOGD("Privilege policy level calculated to : " << policyLevel);
239         if (policyLevel == "Allow") {
240             m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
241             return;
242         }
243         if (policyLevel == "Deny") {
244             m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER);
245             return;
246         }
247         if (policyLevel != "Ask user") {
248             ALOGE("Unknown policy set : " << policyLevel << " for (" << conn.appId << ", " << conn.user
249                   << ", " << privilege << ")");
250             m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
251             return;
252         }
253
254         auto privacies = privPolicy.getAskablePrivacies();
255         if (privacies.empty()) {
256             ALOGE("All privacies for privilege " << privilege
257                   << " are already allowed");
258             m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
259             return;
260         }
261
262         addEvent(fd, id, privacies);
263         processEvents();
264     } catch (const std::exception &e) {
265         ALOGE("Failed to handle popup request : " << e.what());
266         m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
267     }
268 }
269
270 Logic::~Logic()
271 {
272     m_serverChannel.reset();
273 }
274
275 bool Logic::isEventProcessed() {
276     return m_currentEvent.fd != Protocol::INVALID_FD;
277 }
278
279 void Logic::finishCurrentRequest() {
280     m_eventToPrivaciesSeq.erase(m_currentEvent);
281     m_popupper.popupClose();
282
283     m_currentEvent = EventId();
284     if (!m_pendingEvents.empty())
285         m_pendingEvents.pop_front();
286 }
287
288 void Logic::processEvents() {
289     // Active event processing
290     if (isEventProcessed())
291         return;
292
293     // No pending events
294     if (m_pendingEvents.empty())
295         return;
296
297     FdEvent &fdEvent = m_pendingEvents.front();
298     m_currentEvent = fdEvent.id;
299     fdEvent.event->process();
300 }
301
302 void Logic::registerSignalFd() {
303     // TODO use ecore event EXIT?
304     sigset_t mask;
305     sigemptyset(&mask);
306     sigaddset(&mask, SIGTERM);
307
308     if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
309         throw ErrnoException("Couldn't set signal mask");
310     }
311
312     int signalFd = signalfd(-1, &mask, 0);
313     if (signalFd < 0) {
314         throw ErrnoException("Couldn't create signalfd");
315     }
316     auto handler = ecore_main_fd_handler_add(signalFd, ECORE_FD_READ, &Logic::signalHandler, this, nullptr, nullptr);
317     if (handler == nullptr) {
318         throw Exception("Couldn't set fd handler");
319     }
320 }
321
322 void Logic::stop() {
323     if (isEventProcessed()) {
324         ConnectionInfo &conn = m_connToInfo[m_currentEvent.fd];
325         processResponse(conn, ASKUSER_DENY_ONCE, "Ask user");
326         finishCurrentRequest();
327     }
328     m_popupper.stop();
329 }
330
331 Eina_Bool Logic::signalHandler(void *data, Ecore_Fd_Handler *) {
332     Logic *logic = static_cast<Logic*>(data);
333     logic->stop();
334     return ECORE_CALLBACK_CANCEL;
335 }
336
337 void Logic::startTimer() {
338     if (m_timer)
339         return;
340     ALOGD("Starting timer");
341     m_timer = ecore_timer_add(ASKUSER_IDLE_TIMER_SEC, &Logic::timerHandler, this);
342     if (m_timer == nullptr)
343         ALOGE("Failed to add ecore timer");
344 }
345
346 void Logic::stopTimer() {
347     ALOGD("Stopping timer");
348     if (m_timer == nullptr)
349         return;
350     (void)ecore_timer_del(m_timer);
351     m_timer = nullptr;
352 }
353
354 Eina_Bool Logic::timerHandler(void *data) {
355     Logic *logic = static_cast<Logic*>(data);
356     if (logic->m_connToInfo.empty()) {
357         ALOGD("No connected clients to handle after timer run out. Closing...");
358         logic->stop();
359     }
360     return ECORE_CALLBACK_CANCEL;
361 }
362
363 void Logic::prepareChannel() {
364     AskUser::Protocol::ServerCallbacksPtr callbacks(new AskUser::Protocol::ServerCallbacks(this));
365     std::unique_ptr<AskUser::Protocol::ServerChannel> channel(new AskUser::Protocol::ServerChannel(std::move(callbacks)));
366
367     m_serverChannel = std::move(channel);
368 }
369
370 void Logic::updateChannel(int fd, int mask) {
371     // TODO errors?
372     m_serverChannel->process(fd, mask);
373 }
374
375 void Logic::init() {
376     init_agent_log();
377     m_popupper.initialize();
378     m_popupper.setLocale();
379     m_popupper.registerPopupResponseHandler([&](NResponseType response) { popupResponse(response);});
380
381     registerSignalFd();
382
383     prepareChannel();
384 }
385
386 void Logic::run() {
387     // TODO ensure we won't throw inside ecore loop
388     m_popupper.start();
389     m_popupper.shutdown();
390 }
391
392 bool Logic::setPolicy(const ConnectionInfo &conn, const std::string &lastPolicy) {
393     ALOGD("Setting policy for app " << conn.appId << " with last policy " << lastPolicy);
394     std::string currentPrivacy;
395
396     PrivaciesSequence &privSeq = m_eventToPrivaciesSeq[m_currentEvent];
397     if (!privSeq.getCurrentPrivacy(currentPrivacy) && lastPolicy == "Allow") {
398         ALOGD("Privilege is allowed completely");
399     }
400
401     privSeq.rewind();
402
403     Privacy privacy;
404     while (privSeq.getNextPrivacy(privacy) && privacy != currentPrivacy) {
405         /*
406          * When privacy is not allowed with deny forever or deny once, then processing is stopped,
407          * so all privacies, which were already processed, are allowed.
408          */
409         if (!PolicyUpdater::update(conn.appId, privacy, "Allow")) {
410             // FIXME : Maybe ignore those errors and try to maintain the policy as consistent as we can?
411             ALOGE("Couldn't set policy for " << conn.appId << " privacy : " << privacy << " level : Allow");
412             return false;
413         }
414     }
415
416     if (!currentPrivacy.empty() && lastPolicy != "Ask user") {
417         /*
418          * setPolicy is called when privacy processing is either successfully finished or
419          * aborted due to error, so currentPrivacy will be empty in the first case and
420          * we don't set policy when user responds with "Deny once" (this translates to "Ask user")
421          */
422         if (!PolicyUpdater::update(conn.appId, currentPrivacy, lastPolicy)) {
423             ALOGE("Couldn't set policy for " <<  conn.appId << " privacy : " << privacy << " level : " << lastPolicy);
424         }
425     }
426     return true;
427 }
428
429 void Logic::processResponse(const ConnectionInfo &conn, int clientResponse, const Policy &level) {
430     if (!setPolicy(conn, level)) {
431         m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, ASKUSER_UNKNOWN_ERROR);
432     } else {
433         m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, clientResponse);
434     }
435 }
436
437 void Logic::popupResponse(NResponseType response) {
438     auto it = m_connToInfo.find(m_currentEvent.fd);
439     if (it == m_connToInfo.end()) {
440         ALOGE("Got response from inactive fd " << m_currentEvent.fd);
441         return;
442     }
443     ConnectionInfo &conn = it->second;
444
445     int clientResponse = uiResponseToClientResponse(response);
446     std::string level = clientResponseToPolicy(clientResponse);
447     if (clientResponse != ASKUSER_ALLOW_FOREVER) {
448         // Privacy not allowed, request is denied
449         processResponse(conn, clientResponse, level);
450         finishCurrentRequest();
451
452     } else {
453         // Privacy allowed - check if more privacies are to process
454         PrivaciesSequence &seq = m_eventToPrivaciesSeq[m_currentEvent];
455         Privacy nextPrivacy;
456         if (seq.getNextPrivacy(nextPrivacy)) {
457             // More privacies to process - replace existing event with new privacy
458             FdEvent fdEvent{m_currentEvent, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgLabel, nextPrivacy))};
459             m_pendingEvents[0] = std::move(fdEvent);
460             // don't call finishCurrentRequest here, because it will pop event, which we replaced
461             m_currentEvent = EventId();
462         } else {
463             // No more privacies, request is allowed
464             processResponse(conn, clientResponse, level);
465             finishCurrentRequest();
466         }
467     }
468     processEvents();
469 }
470
471 } // namespace Notification
472
473 } // namepsace AskUser