Add the 'privilege' parameter to popup response callback
[platform/core/security/askuser.git] / src / client / impl / ApiInterfaceImpl.cpp
index 8cc2593..12021ed 100644 (file)
 
 namespace {
 
-int eventsToAskUserMask(int events)
+inline int eventsToAskUserMask(int events)
 {
     return ((events & ASKUSER_READ_EVENT) ? AskUser::Protocol::FdMask::READ : 0) |
            ((events & ASKUSER_WRITE_EVENT) ? AskUser::Protocol::FdMask::WRITE : 0);
 }
 
-int askUserMaskToEvents(int mask)
+inline int askUserMaskToEvents(int mask)
 {
     return ((AskUser::Protocol::FdMask::READ & mask) ? ASKUSER_READ_EVENT : 0) |
            ((AskUser::Protocol::FdMask::WRITE & mask) ? ASKUSER_WRITE_EVENT : 0);
 }
 
-askuser_popup_result responseToAskUserPopupResult(int response)
+inline askuser_popup_result responseToAskUserPopupResult(int response)
 {
     switch (response) {
         case ASKUSER_ALLOW_FOREVER:
@@ -59,6 +59,15 @@ askuser_popup_result responseToAskUserPopupResult(int response)
     return ASKUSER_POPUP_RESULT_DENY_ONCE;
 }
 
+inline askuser_call_cause deduceCauseFromResponse(int response)
+{
+    if (response == ASKUSER_UNKNOWN_ERROR) {
+        return ASKUSER_CALL_CAUSE_ERROR;
+    }
+
+    return ASKUSER_CALL_CAUSE_ANSWER;
+}
+
 } // namespace
 
 namespace AskUser {
@@ -75,12 +84,8 @@ ApiInterfaceImpl::ApiInterfaceImpl(const StatusCallbackClosure &statusClosure)
 
 ApiInterfaceImpl::~ApiInterfaceImpl()
 {
-    for (const auto &closure : m_callbacks) {
-        closure.second(closure.first, askuser_call_cause::ASKUSER_CALL_CAUSE_FINALIZE,
-                       askuser_popup_result::ASKUSER_POPUP_RESULT_DENY_ONCE);
-    }
+    respondToAllRequests(ASKUSER_CALL_CAUSE_FINALIZE, ASKUSER_POPUP_RESULT_DENY_ONCE);
 
-    m_callbacks.clear();
     m_channel.reset();
 }
 
@@ -102,7 +107,8 @@ askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privile
     auto policies = fetch.fetchPolicy();
 
     if (policies.size() != 1) {
-        ALOGE("Unusual situation, there are " << policies.size() << " policies for (" << appId << ", " << geteuid() << ", " << privilege << ")");
+        ALOGE("Unusual situation, there are " << policies.size() <<
+              " policies for (" << appId << ", " << geteuid() << ", " << privilege << ")");
         return ASKUSER_CHECK_RESULT_DENY;
     }
 
@@ -126,48 +132,70 @@ askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privile
 RequestId ApiInterfaceImpl::popupRequest(const PopupCallbackClosure &closure,
                                          const std::string &privilege)
 {
-    Client::RequestId id = static_cast<Client::RequestId>(m_channel->popupRequest(privilege));
+    RequestId id = static_cast<RequestId>(m_channel->popupRequest(privilege));
+
+    auto it = m_popupClosures.find(id);
+    if (it != m_popupClosures.end()) {
+        ALOGE("Popup closure exists for id: " << id <<
+              " privilege: " << it->second.privilege() << ", replacing");
+        popupResponse(id, ASKUSER_UNKNOWN_ERROR);
+    }
 
-    auto it = m_callbacks.find(id);
-    if (it != m_callbacks.end()) {
-        it->second(it->first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
-        m_callbacks.erase(it);
+    if (popupRequestInProgress(privilege)) {
+        ALOGE("Privilege " << closure.privilege() << " already exists in the pending privileges set");
     }
 
-    m_callbacks.insert({id, closure});
+    m_requestedPrivileges.insert(privilege);
+    m_popupClosures.insert({id, closure});
 
     return id;
 }
 
+bool ApiInterfaceImpl::popupRequestInProgress(const std::string &privilege) const
+{
+    return m_requestedPrivileges.find(privilege) != m_requestedPrivileges.end();
+}
+
 void ApiInterfaceImpl::updateConnection(Protocol::ConnectionFd fd, int mask)
 {
     m_statusClosure(fd, askUserMaskToEvents(mask));
 
-    // remove all pending events
+    // the connection is about to close, respond to all pending requests
     if (mask == ASKUSER_EMPTY_EVENTS) {
-        for (const auto &closure : m_callbacks) {
-            closure.second(closure.first, ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
-        }
-
-        m_callbacks.clear();
+        respondToAllRequests(ASKUSER_CALL_CAUSE_ERROR, ASKUSER_POPUP_RESULT_DENY_ONCE);
     }
 }
 
 void ApiInterfaceImpl::popupResponse(Protocol::RequestId id, int response)
 {
-    auto it = m_callbacks.find(id);
-    if (it == m_callbacks.end()) {
+    auto it = m_popupClosures.find(id);
+    if (it == m_popupClosures.end()) {
+        ALOGE("Couldn't find popup callback closure for id: " << id);
         return;
     }
 
-    askuser_call_cause cause = ASKUSER_CALL_CAUSE_ANSWER;
-    if (response == ASKUSER_UNKNOWN_ERROR) {
-        cause = ASKUSER_CALL_CAUSE_ERROR;
+    const auto &closure = it->second;
+    if (!popupRequestInProgress(closure.privilege())) {
+        ALOGE("Couldn't find privilege " << closure.privilege() << " in the pending privileges set");
     }
 
+    askuser_call_cause cause = deduceCauseFromResponse(response);
     askuser_popup_result res = responseToAskUserPopupResult(response);
-    it->second(id, cause, res);
-    m_callbacks.erase(it);
+
+    closure(id, cause, res);
+
+    m_requestedPrivileges.erase(closure.privilege());
+    m_popupClosures.erase(it);
+}
+
+void ApiInterfaceImpl::respondToAllRequests(askuser_call_cause cause, askuser_popup_result result)
+{
+    for (const auto &closure : m_popupClosures) {
+        closure.second(closure.first, cause, result);
+    }
+
+    m_requestedPrivileges.clear();
+    m_popupClosures.clear();
 }
 
 } // namespace Client