2 * Copyright (c) 2017-2018 Samsung Electronics Co.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * @author Zofia Grzelewska <z.abramowska@samsung.com>
19 * @brief Declaration of Logic class
27 #include <sys/signalfd.h>
29 #include <Elementary.h>
31 #include <exception/Exception.h>
32 #include <exception/ErrnoException.h>
33 #include <policy/Policy.h>
34 #include <policy/PrivilegePolicy.h>
36 #include "PolicyUpdater.h"
37 #include "ServerCallbacks.h"
41 namespace Notification {
45 int ASKUSER_IDLE_TIMER_SEC = 4;
47 int uiResponseToClientResponse(NResponseType response) {
51 case NResponseType::Deny:
52 clientResponse = ASKUSER_DENY_ONCE;
54 case NResponseType::DenyAlways:
55 clientResponse = ASKUSER_DENY_FOREVER;
57 case NResponseType::Allow:
58 case NResponseType::AllowAlways:
59 clientResponse = ASKUSER_ALLOW_FOREVER;
61 case NResponseType::None:
62 clientResponse = ASKUSER_NONE;
64 case NResponseType::Error:
65 clientResponse = ASKUSER_UNKNOWN_ERROR;
68 clientResponse = ASKUSER_UNKNOWN_ERROR;
71 return clientResponse;
74 std::string clientResponseToPolicy(int clientResponse) {
77 switch (clientResponse) {
78 case ASKUSER_DENY_FOREVER:
81 case ASKUSER_ALLOW_FOREVER:
93 void Logic::addChannelFd(Protocol::ConnectionFd fd, const Protocol::Credentials &creds) {
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);
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);
108 std::string appId, pkgLabel;
109 PkgMgrPkgInfo pkgInfo;
110 identifyApp(pkgInfo, creds.label, appId, pkgLabel);
112 ALOGD("Proper client connected");
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);
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);
129 m_fdInfo[fd].status = FdChange::NONE;
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;
138 m_fdInfo[fd].handler = handler;
141 void Logic::removeChannelFd(Protocol::ConnectionFd fd) {
142 ALOGD("Removing channel with fd " << fd);
143 m_connToInfo.erase(fd);
145 if (m_connToInfo.empty()) {
146 ALOGD("No more clients");
149 auto it = m_fdInfo.find(fd);
150 if (it == m_fdInfo.end()) {
153 it->second.status = FdChange::DEL;
154 ecore_main_fd_handler_del(it->second.handler);
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);
161 ALOGE("Failed to fetch fd from handler");
162 return ECORE_CALLBACK_CANCEL;
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;
170 return service->processChannel(fd, mask);
173 Eina_Bool Logic::processChannel(int fd, int mask) {
174 ALOGD("Porcesing fd " << fd << " with mask " << mask);
175 updateChannel(fd, mask);
177 switch (m_fdInfo[fd].status) {
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());
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);
192 m_serverChannel->process(fd, 0);
194 // Handle next event if removed active fd
195 if (fd == m_currentEvent.fd) {
196 finishCurrentRequest();
199 return ECORE_CALLBACK_CANCEL;
201 case FdChange::CHANGE:
202 return ECORE_CALLBACK_CANCEL;
204 ALOGE("Unexpected fd change value : " << static_cast<int>(m_fdInfo[fd].status));
205 return ECORE_CALLBACK_CANCEL;
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);
214 ConnectionInfo &conn = m_connToInfo[fd];
216 Privacy currentPrivacy;
217 seq.getNextPrivacy(currentPrivacy);
219 FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgLabel, currentPrivacy))};
220 m_pendingEvents.emplace_back(std::move(fdEvent));
223 void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::string &privilege) {
225 ALOGD("Request for privilege " << privilege << " from fd " << fd << " with id " << id);
227 auto it = m_connToInfo.find(fd);
228 if (it == m_connToInfo.end()) {
229 ALOGE("Got request to non existing fd " << fd);
232 ConnectionInfo &conn = it->second;
234 PrivilegePolicy privPolicy(conn.appId, privilege);
235 PkgMgrAppInfo appInfo;
236 auto policyLevel = privPolicy.calculatePolicy(appInfo);
238 ALOGD("Privilege policy level calculated to : " << policyLevel);
239 if (policyLevel == "Allow") {
240 m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
243 if (policyLevel == "Deny") {
244 m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER);
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);
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);
262 addEvent(fd, id, privacies);
264 } catch (const std::exception &e) {
265 ALOGE("Failed to handle popup request : " << e.what());
266 m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
272 m_serverChannel.reset();
275 bool Logic::isEventProcessed() {
276 return m_currentEvent.fd != Protocol::INVALID_FD;
279 void Logic::finishCurrentRequest() {
280 m_eventToPrivaciesSeq.erase(m_currentEvent);
281 m_popupper.popupClose();
283 m_currentEvent = EventId();
284 if (!m_pendingEvents.empty())
285 m_pendingEvents.pop_front();
288 void Logic::processEvents() {
289 // Active event processing
290 if (isEventProcessed())
294 if (m_pendingEvents.empty())
297 FdEvent &fdEvent = m_pendingEvents.front();
298 m_currentEvent = fdEvent.id;
299 fdEvent.event->process();
302 void Logic::registerSignalFd() {
303 // TODO use ecore event EXIT?
306 sigaddset(&mask, SIGTERM);
308 if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
309 throw ErrnoException("Couldn't set signal mask");
312 int signalFd = signalfd(-1, &mask, 0);
314 throw ErrnoException("Couldn't create signalfd");
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");
323 if (isEventProcessed()) {
324 ConnectionInfo &conn = m_connToInfo[m_currentEvent.fd];
325 processResponse(conn, ASKUSER_DENY_ONCE, "Ask user");
326 finishCurrentRequest();
331 Eina_Bool Logic::signalHandler(void *data, Ecore_Fd_Handler *) {
332 Logic *logic = static_cast<Logic*>(data);
334 return ECORE_CALLBACK_CANCEL;
337 void Logic::startTimer() {
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");
346 void Logic::stopTimer() {
347 ALOGD("Stopping timer");
348 if (m_timer == nullptr)
350 (void)ecore_timer_del(m_timer);
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...");
360 return ECORE_CALLBACK_CANCEL;
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)));
367 m_serverChannel = std::move(channel);
370 void Logic::updateChannel(int fd, int mask) {
372 m_serverChannel->process(fd, mask);
377 m_popupper.initialize();
378 m_popupper.setLocale();
379 m_popupper.registerPopupResponseHandler([&](NResponseType response) { popupResponse(response);});
387 // TODO ensure we won't throw inside ecore loop
389 m_popupper.shutdown();
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;
396 PrivaciesSequence &privSeq = m_eventToPrivaciesSeq[m_currentEvent];
397 if (!privSeq.getCurrentPrivacy(currentPrivacy) && lastPolicy == "Allow") {
398 ALOGD("Privilege is allowed completely");
404 while (privSeq.getNextPrivacy(privacy) && privacy != currentPrivacy) {
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.
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");
416 if (!currentPrivacy.empty() && lastPolicy != "Ask user") {
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")
422 if (!PolicyUpdater::update(conn.appId, currentPrivacy, lastPolicy)) {
423 ALOGE("Couldn't set policy for " << conn.appId << " privacy : " << privacy << " level : " << lastPolicy);
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);
433 m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, clientResponse);
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);
443 ConnectionInfo &conn = it->second;
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();
453 // Privacy allowed - check if more privacies are to process
454 PrivaciesSequence &seq = m_eventToPrivaciesSeq[m_currentEvent];
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();
463 // No more privacies, request is allowed
464 processResponse(conn, clientResponse, level);
465 finishCurrentRequest();
471 } // namespace Notification
473 } // namepsace AskUser