Add caching of App/Pkg data & use faster way to retrieve this data
[platform/core/security/askuser.git] / src / client / impl / ApiInterfaceImpl.cpp
1 /*
2  *  Copyright (c) 2017 - 2018 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 /**
18  * @file        ApiInterfaceImpl.cpp
19  * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
20  * @author      Zofia Grzelewska <z.abramowska@samsung.com>
21  * @brief       The definition of ApiInterfaceImpl.
22  */
23
24 #include <algorithm>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include <log/alog.h>
29 #include <policy/Policy.h>
30 #include <policy/PrivilegePolicy.h>
31 #include <client-channel.h>
32 #include <common-types.h>
33
34 #include "ClientCallbacks.h"
35 #include "ApiInterfaceImpl.h"
36
37 namespace {
38
39 inline int eventsToAskUserMask(int events)
40 {
41     return ((events & ASKUSER_READ_EVENT) ? AskUser::Protocol::FdMask::READ : 0) |
42            ((events & ASKUSER_WRITE_EVENT) ? AskUser::Protocol::FdMask::WRITE : 0);
43 }
44
45 inline int askUserMaskToEvents(int mask)
46 {
47     return ((AskUser::Protocol::FdMask::READ & mask) ? ASKUSER_READ_EVENT : 0) |
48            ((AskUser::Protocol::FdMask::WRITE & mask) ? ASKUSER_WRITE_EVENT : 0);
49 }
50
51 inline askuser_popup_result responseToAskUserPopupResult(int response)
52 {
53     switch (response) {
54         case ASKUSER_ALLOW_FOREVER:
55             return ASKUSER_POPUP_RESULT_ALLOW_FOREVER;
56         case ASKUSER_DENY_FOREVER:
57             return ASKUSER_POPUP_RESULT_DENY_FOREVER;
58         case ASKUSER_DENY_ONCE:
59             return ASKUSER_POPUP_RESULT_DENY_ONCE;
60     }
61
62     return ASKUSER_POPUP_RESULT_DENY_ONCE;
63 }
64
65 inline askuser_call_cause deduceCauseFromResponse(int response)
66 {
67     if (response == ASKUSER_UNKNOWN_ERROR) {
68         return ASKUSER_CALL_CAUSE_ERROR;
69     }
70
71     return ASKUSER_CALL_CAUSE_ANSWER;
72 }
73
74 } // namespace
75
76 namespace AskUser {
77
78 namespace Client {
79
80 ApiInterfaceImpl::ApiInterfaceImpl(const StatusCallbackClosure &statusClosure)
81 : m_statusClosure(statusClosure)
82 {
83     Protocol::ClientCallbacksPtr callbacks(new ClientCallbacks(this));
84     std::unique_ptr<Protocol::ClientChannel> channel(new Protocol::ClientChannel(std::move(callbacks)));
85     m_channel = std::move(channel);
86 }
87
88 ApiInterfaceImpl::~ApiInterfaceImpl()
89 {
90     respondToAllRequests(ASKUSER_CALL_CAUSE_FINALIZE, ASKUSER_POPUP_RESULT_DENY_ONCE);
91
92     m_channel.reset();
93 }
94
95 int ApiInterfaceImpl::process(int fd, int events)
96 {
97     return m_channel->process(fd, eventsToAskUserMask(events));
98 }
99
100 askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege)
101 {
102     std::string appId = getOwnAppId(m_pkgInfo);
103     PrivilegePolicy privPolicy(appId, privilege);
104     auto policyLevel = privPolicy.calculatePolicy(m_appInfo);
105
106     if (policyLevel == "Allow") {
107         return ASKUSER_CHECK_RESULT_ALLOW;
108     }
109
110     if (policyLevel == "Deny") {
111         return ASKUSER_CHECK_RESULT_DENY;
112     }
113
114     if (policyLevel == "Ask user") {
115         return ASKUSER_CHECK_RESULT_ASK;
116     }
117
118     ALOGE("Unknown policy level set : " << policyLevel <<
119           " for app " << appId << " and privilege " << privilege);
120     return ASKUSER_CHECK_RESULT_DENY;
121 }
122
123 RequestId ApiInterfaceImpl::popupRequest(const std::string &privilege,
124                                          const askuser_popup_response_callback callback,
125                                          void *userData)
126 {
127     Protocol::ConnectionContext conCtx = m_channel->popupRequest(privilege);
128
129     auto sameRequest = [&] (const Request &req) {
130         return req.m_requestId == conCtx.m_requestId;
131     };
132
133     auto reqIt = std::find_if(m_requests.begin(), m_requests.end(), sameRequest);
134     if (reqIt != m_requests.end()) {
135         ALOGE("Popup closure exists for id: " << conCtx.m_requestId <<
136               " privilege: " << reqIt->m_privilege << ", replacing");
137         popupResponse(conCtx.m_requestId, ASKUSER_UNKNOWN_ERROR);
138     }
139
140     if (popupRequestInProgress(privilege)) {
141         ALOGE("Privilege " << privilege << " already exists in the pending requests");
142     }
143
144     m_requests.push_back({ conCtx.m_requestId, conCtx.m_fd, privilege, callback, userData });
145
146     return conCtx.m_requestId;
147 }
148
149 bool ApiInterfaceImpl::popupRequestInProgress(const std::string &privilege) const
150 {
151     auto samePrivilege = [&] (const Request &req) {
152         return req.m_privilege == privilege;
153     };
154
155     return std::find_if(m_requests.begin(), m_requests.end(), samePrivilege) != m_requests.end();
156 }
157
158 void ApiInterfaceImpl::updateConnection(Protocol::ConnectionFd fd, int mask)
159 {
160     m_statusClosure(fd, askUserMaskToEvents(mask));
161
162     if (mask == ASKUSER_EMPTY_EVENTS) {
163         auto sameFd = [&] (const Request &req) {
164             return req.m_fd == fd;
165         };
166
167         auto reqIt = std::find_if(m_requests.begin(), m_requests.end(), sameFd);
168         if (reqIt == m_requests.end()) {
169             return;
170         }
171
172         ALOGW("askuser-notification has been unexpectedly stopped, "
173               "sending the error response for privilege: "
174               << reqIt->m_privilege << " id: " << reqIt->m_requestId);
175
176         popupResponse(reqIt->m_requestId, ASKUSER_UNKNOWN_ERROR);
177     }
178 }
179
180 void ApiInterfaceImpl::popupResponse(Protocol::RequestId id, int response)
181 {
182     auto sameRequestId = [&] (const Request &req) {
183         return req.m_requestId == id;
184     };
185
186     auto reqIt = std::find_if(m_requests.begin(), m_requests.end(), sameRequestId);
187     if (reqIt == m_requests.end()) {
188         ALOGE("Couldn't find request for id: " << id);
189         return;
190     }
191
192     askuser_call_cause cause = deduceCauseFromResponse(response);
193     askuser_popup_result res = responseToAskUserPopupResult(response);
194
195     reqIt->m_callback(id, cause, res, reqIt->m_privilege.c_str(), reqIt->m_userData);
196
197     m_requests.erase(reqIt);
198 }
199
200 void ApiInterfaceImpl::respondToAllRequests(askuser_call_cause cause, askuser_popup_result result)
201 {
202     for (const auto &req : m_requests) {
203         req.m_callback(req.m_requestId, cause, result,
204                        req.m_privilege.c_str(), req.m_userData);
205     }
206
207     m_requests.clear();
208 }
209
210 } // namespace Client
211
212 } // namespace AskUser