Return ALLOW for non privacy privileges 12/171312/14
authorZofia Grzelewska <z.abramowska@samsung.com>
Tue, 27 Feb 2018 15:27:14 +0000 (16:27 +0100)
committerTomasz Swierczek <t.swierczek@samsung.com>
Thu, 19 Apr 2018 06:56:08 +0000 (06:56 +0000)
When application checks/requests permission for given privilege,
return ALLOW when this privilege is requested by application
in manifest, but isn't privacy for it.

Change-Id: Ia36478fce3b9737589c2c130b9247ee3e7a89143

src/client/impl/ApiInterfaceImpl.cpp
src/common/CMakeLists.txt
src/common/policy/Policy.cpp
src/common/policy/Policy.h
src/common/policy/PrivilegeInfo.cpp
src/common/policy/PrivilegeInfo.h
src/common/policy/PrivilegePolicy.cpp [new file with mode: 0644]
src/common/policy/PrivilegePolicy.h [new file with mode: 0644]
src/notification-daemon/CMakeLists.txt
src/notification-daemon/Logic.cpp

index 79619a2..c653312 100644 (file)
@@ -17,6 +17,7 @@
 /**
  * @file        ApiInterfaceImpl.cpp
  * @author      Piotr Sawicki <p.sawicki2@partner.samsung.com>
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
  * @brief       The definition of ApiInterfaceImpl.
  */
 
@@ -26,6 +27,7 @@
 
 #include <log/alog.h>
 #include <policy/Policy.h>
+#include <policy/PrivilegePolicy.h>
 #include <client-channel.h>
 #include <common-types.h>
 
@@ -98,13 +100,9 @@ int ApiInterfaceImpl::process(int fd, int events)
 askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege)
 {
     std::string appId = getOwnAppId();
+    PrivilegePolicy privPolicy(appId, privilege);
+    auto policyLevel = privPolicy.calculatePolicy();
 
-    auto policyLevel = getPrivilegeMappedPolicy(appId, privilege);
-
-    if (policyLevel.empty()) {
-        ALOGD("Privilege " << privilege << " is not a privacy privilege for app " << appId);
-        return ASKUSER_CHECK_RESULT_DENY;
-    }
     if (policyLevel == "Allow") {
         return ASKUSER_CHECK_RESULT_ALLOW;
     }
index 4adb6f8..b43a147 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2018 Samsung Electronics Co., Ltd All Rights Reserved
 #
 #    Licensed under the Apache License, Version 2.0 (the "License");
 #    you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ PKG_CHECK_MODULES(COMMON_DEP
     REQUIRED
     security-manager
     pkgmgr-info
+    security-privilege-manager
     )
 
 SET(ASKUSER_COMMON_VERSION_MAJOR 0)
@@ -39,6 +40,7 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/log/alog.cpp
     ${COMMON_PATH}/policy/Policy.cpp
     ${COMMON_PATH}/policy/PrivilegeInfo.cpp
+    ${COMMON_PATH}/policy/PrivilegePolicy.cpp
     ${COMMON_PATH}/types/AgentErrorMsg.cpp
     ${COMMON_PATH}/util/SafeFunction.cpp
     ${COMMON_PATH}/config/Limits.cpp
index 6af0e66..5f1954a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016-2017 Samsung Electronics Co.
+ *  Copyright (c) 2016-2018 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
  */
 /**
  * @file        src/agent/main/Policy.cpp
- * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
  * @brief       Implementation of Policy wrappers
  */
 
@@ -70,41 +70,27 @@ PolicyEntryCopy::PolicyEntryCopy(policy_entry *entry) {
     m_level = level;
 }
 
-Policy getMinimumPolicy(const std::vector<Policy> &policies) {
-    if (policies.empty())
-        return "";
-
-    Policy minimumPolicy = "Allow";
-
-    for (auto &policy : policies) {
-        if (policy == "Deny") {
-            minimumPolicy = "Deny";
-            break;
-        } else if (policy != minimumPolicy && policy == "Ask user") {
-            minimumPolicy = "Ask user";
-        }
+std::set<Privilege> getManifestPrivs(const std::string &appId)
+{
+    char **privsRaw;
+    size_t privsCount;
+
+    int ret = security_manager_get_app_manifest_policy(appId.c_str(), geteuid(),
+                                                       &privsRaw, &privsCount);
+    if (ret != SECURITY_MANAGER_SUCCESS) {
+        ALOGE("Failed to fetch manifest privileges for app " << appId << " : " << ret);
+        return {};
     }
-    return minimumPolicy;
-}
-
-Policy calculatePolicyForPrivacy(const std::string &appId, const Privacy &privacy) {
-    ALOGD("Calculating privacy " << privacy);
-    std::vector<Policy> privsPolicies;
-    auto privileges = PrivilegeInfo::getPrivacyPrivileges(privacy);
-    for (const auto &privilege : privileges) {
-        ALOGD("Calculating policy for privilege " << privilege);
-
-        std::string policyLevel = getPrivilegePolicy(appId, privilege);
-
-        if (policyLevel.empty()) {
-            ALOGE("Couldn't get policy level, skipping");
-            continue;
-        }
-
-        ALOGD("Fetched policy level : " << policyLevel);
-        privsPolicies.push_back(std::move(policyLevel));
+    auto privsFree = [privsCount](char ** privs) {
+        security_manager_privileges_free(privs, privsCount);
+    };
+    std::unique_ptr<char *, decltype(privsFree)> privsPtr(privsRaw, privsFree);
+    std::set<Privilege> privileges;
+
+    for (size_t i = 0; i < privsCount; i++) {
+        privileges.insert(privsRaw[i]);
     }
-    return getMinimumPolicy(privsPolicies);
+    return privileges;
 }
 
 Policy getPrivilegePolicy(const std::string &appId, const Privilege &privilege) {
@@ -127,15 +113,14 @@ Policy getPrivilegePolicy(const std::string &appId, const Privilege &privilege)
     return policies[0].getLevel();
 }
 
-Policy getPrivaciesPolicy(const std::string &appId, const std::vector<Privacy> &privacies) {
-    std::vector<Policy> policies;
-    for (auto &privacy : privacies) {
-        Policy privacyPolicy = calculatePolicyForPrivacy(appId, privacy);
-        if (privacyPolicy.empty())
-            continue;
-        policies.push_back(privacyPolicy);
-    }
-    return getMinimumPolicy(policies);
+std::vector<PolicyEntryCopy> getAppPolicy(const std::string &appId) {
+    PolicyEntry filter;
+    filter.setApp(appId);
+    filter.setUser(std::to_string(geteuid()));
+    filter.setPrivilege(SECURITY_MANAGER_ANY);
+
+    PolicyFetchRequest fetch(std::move(filter));
+    return fetch.fetchPolicy();
 }
 
 void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel)
@@ -162,16 +147,6 @@ void identifyApp(const std::string &client, std::string &appId, std::string &pkg
     pkgLabel = pkgInfo.pkgLabel();
 }
 
-Policy getPrivilegeMappedPolicy(const std::string &appId, const std::string &privilege) {
-    std::vector<Privacy> privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(appId, privilege);
-    if (privacies.empty()) {
-        ALOGE("Privilege doesn't map to any privacy");
-        return "";
-    }
-
-    return getPrivaciesPolicy(appId, privacies);
-}
-
 std::string getOwnAppId()
 {
     char *pkgName = nullptr;
index 300fa52..132d067 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016-2017 Samsung Electronics Co.
+ *  Copyright (c) 2016-2018 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
  */
 /**
  * @file        src/agent/main/Policy.h
- * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
  * @brief       Definition of Policy wrappers
  */
 
 #pragma once
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -31,16 +32,16 @@ struct policy_update_req;
 
 namespace AskUser {
 
+class PolicyEntryCopy;
+
 std::string getOwnAppId();
 void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel);
 
-Policy calculatePolicyForPrivacy(const std::string &appId, const Privacy &privacy);
-Policy getMinimumPolicy(const std::vector<Policy> &policies);
-Policy getPrivilegeMappedPolicy(const std::string &appId, const Privilege &privilege);
-Policy getPrivaciesPolicy(const std::string &appId, const std::vector<Privacy> &privacies);
+std::set<Privilege> getManifestPrivs(const std::string &appId);
 
 Policy getPrivilegePolicy(const std::string &appId, const Privilege &corePrivilege);
 
+std::vector<PolicyEntryCopy> getAppPolicy(const std::string &appId);
 
 class PolicyEntry {
 public:
index 200e068..9a3e9b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 Samsung Electronics Co.
+ *  Copyright (c) 2016-2018 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
  */
 /**
  * @file        src/agent/notification-daemon/Privilege.cpp
- * @author      Zofia Abramowska <z.abramowska@samsung.com>
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
  * @brief       Implementation of Privilege Info wrappers
  */
 
@@ -23,6 +23,7 @@
 #include <memory>
 #include <set>
 
+#include "Policy.h"
 #include "PrivilegeInfo.h"
 
 #include <exception/Exception.h>
 
 #include <privilegemgr/privilege_info.h>
 #include <privilegemgr/privilege_db_manager.h>
-#include <pkgmgr-info.h>
 #include <glib.h>
 
-
 namespace AskUser {
 
 namespace PrivilegeInfo {
@@ -69,6 +68,20 @@ private:
     GList *m_head;
 };
 
+Privacy getPrivacyName(const Privilege &privilege) {
+    char* privacyName = nullptr;
+    int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName);
+    if (ret != PRVMGR_ERR_NONE || !privacyName) {
+        ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">");
+        return privilege;
+    }
+
+    std::unique_ptr<char, decltype(free) *> privacyNamePtr(privacyName, free);
+    return std::string(privacyName);
+}
+
+} //namespace anonymous
+
 std::vector<Privacy> getPrivilegesPrivacies(const std::vector<std::string> &corePrivileges) {
     std::set<Privacy> privaciesSet;
     for (auto &privilege : corePrivileges) {
@@ -133,9 +146,6 @@ std::vector<Privilege> getPrivilegeMapping(const std::string &appId, const Privi
     return privMappedVector;
 }
 
-
-} //namespace anonymous
-
 bool isPrivacy(const Privilege &privilege) {
     return privilege_info_is_privacy(privilege.c_str()) == 1;
 }
@@ -151,18 +161,6 @@ std::string getPrivacyDisplayName(const Privacy &privacy) {
     return std::string(displayName);
 }
 
-Privacy getPrivacyName(const Privilege &privilege) {
-    char* privacyName = nullptr;
-    int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName);
-    if (ret != PRVMGR_ERR_NONE || !privacyName) {
-        ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">");
-        return privilege;
-    }
-
-    std::unique_ptr<char, decltype(free) *> privacyNamePtr(privacyName, free);
-    return std::string(privacyName);
-}
-
 std::vector<Privilege> getPrivacyPrivileges(const Privacy &privacy) {
     GList *privilegeList = nullptr;
 
@@ -180,16 +178,5 @@ std::vector<Privilege> getPrivacyPrivileges(const Privacy &privacy) {
     return privVector;
 }
 
-
-std::vector<Privacy> getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege) {
-    std::vector<std::string> corePrivileges = PrivilegeInfo::getPrivilegeMapping(appId, privilege);
-    if (corePrivileges.empty()) {
-        ALOGE("Cannot fetch mapping for application " << appId << " and privilege " << privilege << ", aborting");
-        return {};
-    }
-
-    return getPrivilegesPrivacies(corePrivileges);
-}
-
 }
 } /* namespace AskUser */
index 06d714e..fa651bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2016 Samsung Electronics Co.
+ *  Copyright (c) 2016-2018 Samsung Electronics Co.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
  *  limitations under the License
  */
 /**
- * @file        src/agent/notification-daemon/Privilege.h
- * @author      Zofia Abramowska <z.abramowska@samsung.com>
- * @brief       Definition of Privilege Info wrappers
+ * @file        PrivilegeInfo.h
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief       Definition of Privilege Info wrappers.
  */
 
 #pragma once
 namespace AskUser {
 
 namespace PrivilegeInfo {
-    std::vector<Privacy> getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege);
+    std::vector<Privilege> getPrivilegeMapping(const std::string &appId,
+                                               const Privilege &privilege);
+    std::vector<Privacy> getPrivilegesPrivacies(const std::vector<std::string> &corePrivileges);
     bool isPrivacy(const Privilege &privilege);
-    Privacy getPrivacyName(const Privacy &privilege);
+
     std::string getPrivacyDisplayName(const Privacy &privacy);
 
     std::vector<Privilege> getPrivacyPrivileges(const Privacy &privacy);
diff --git a/src/common/policy/PrivilegePolicy.cpp b/src/common/policy/PrivilegePolicy.cpp
new file mode 100644 (file)
index 0000000..66dc203
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/**
+ * @file        PrivilegePolicy.cpp
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief       The implementation of PrivilegePolicy class.
+ */
+
+
+#include <glib.h>
+#include <memory>
+#include <set>
+
+#include <log/alog.h>
+#include <policy/AppInfo.h>
+#include <policy/Policy.h>
+#include <policy/PrivilegeInfo.h>
+
+#include "PrivilegePolicy.h"
+
+namespace AskUser {
+
+namespace {
+bool updateMinimal(const Policy &current, Policy &minimal) {
+    if (current == "Deny") {
+        minimal = "Deny";
+        return false;
+    } else if (current != minimal && current == "Ask user") {
+        minimal = "Ask user";
+    }
+    return true;
+}
+
+Policy calculatePrivsPolicy(const std::vector<Privilege> &privs,
+                            const std::unordered_map<Privilege, Policy> &policyMap) {
+    Policy minimalPolicy = "Allow";
+    bool policyExists = false;
+
+    for (auto & priv : privs) {
+        auto it = policyMap.find(priv);
+        if (it == policyMap.end()) {
+            ALOGD("Application has no privacy policy for privilege " << priv);
+            continue;
+        }
+        policyExists = true;
+        if (!updateMinimal(it->second, minimalPolicy))
+            break;
+    }
+
+    if (!policyExists)
+        return "";
+
+    return minimalPolicy;
+}
+
+} // anonymous namespace
+
+PrivilegePolicy::PrivilegePolicy(const std::string &appId, const Privilege &privilege)
+    : m_appId(appId),
+      m_privilege(privilege)
+{}
+
+Policy PrivilegePolicy::calculatePolicy() {
+    std::vector<Privilege> corePrivileges =
+            PrivilegeInfo::getPrivilegeMapping(m_appId, m_privilege);
+    if (corePrivileges.empty()) {
+        ALOGE("Privilege " << m_privilege << " doesn't map to any core privilege");
+        return "Deny";
+    }
+
+    // Check if application requested core privileges in manifest
+    std::set<Privilege> manifestPrivs = getManifestPrivs(m_appId);
+    for (auto &corePriv : corePrivileges) {
+        if (manifestPrivs.find(corePriv) == manifestPrivs.end()) {
+            ALOGE("Application " << m_appId << " didn't request privilege "
+                  << corePriv << " in its manifest");
+            return "Deny";
+        }
+    }
+    std::vector<Privacy> privacies = PrivilegeInfo::getPrivilegesPrivacies(corePrivileges);
+    if (privacies.empty()) {
+        ALOGE("Privilege doesn't map to any privacy");
+        return "Allow";
+    }
+
+    return calculatePrivaciesPolicy(privacies);
+}
+
+
+Policy PrivilegePolicy::calculatePrivaciesPolicy(const std::vector<Privacy> &privacies) {
+    std::unordered_map<Privacy, std::vector<Privilege>> privacyPrivileges;
+    std::unordered_map<Privilege, Policy> privilegePolicy;
+
+    for (auto &privacy : privacies) {
+        auto privileges = PrivilegeInfo::getPrivacyPrivileges(privacy);
+        privacyPrivileges[privacy] = privileges;
+    }
+
+    auto policies = getAppPolicy(m_appId);
+
+    for (auto &policy : policies) {
+        privilegePolicy[policy.getPrivilege()] = policy.getLevel();
+    }
+
+    m_askablePrivacies.clear();
+    Policy totalPolicy = "Allow";
+    for (auto &privacy : privacies) {
+        Policy policy = calculatePrivsPolicy(privacyPrivileges[privacy], privilegePolicy);
+        if (policy.empty()) {
+            ALOGD("Privacy group " << privacy << " is not privacy for application " << m_appId);
+            policy = "Allow";
+        }
+        if (policy == "Ask user") {
+            m_askablePrivacies.push_back(privacy);
+        }
+        if (!updateMinimal(policy, totalPolicy))
+            break;
+    }
+
+    if (totalPolicy == "Deny")
+        m_askablePrivacies.clear();
+
+    return totalPolicy;
+}
+
+}
diff --git a/src/common/policy/PrivilegePolicy.h b/src/common/policy/PrivilegePolicy.h
new file mode 100644 (file)
index 0000000..c22e45b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/**
+ * @file        PrivilegePolicy.h
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief       The definition of PrivilegePolicy class.
+ */
+
+#include <unordered_map>
+#include <string>
+#include <vector>
+
+#include <types/PolicyTypes.h>
+
+namespace AskUser {
+
+class PrivilegePolicy {
+public:
+    PrivilegePolicy(const std::string &appId, const Privilege &privilege);
+    Policy calculatePolicy();
+    std::vector<Privacy> getAskablePrivacies() const {
+        return m_askablePrivacies;
+    }
+private:
+    Policy calculatePrivaciesPolicy(const std::vector<Privacy> &privacies);
+    std::string m_appId;
+    Privilege m_privilege;
+
+    std::vector<Privacy> m_askablePrivacies;
+};
+
+}
index fba96a9..c01f1ea 100644 (file)
@@ -12,7 +12,6 @@ PKG_CHECK_MODULES(ASKUSER_NOTIFICATION_DEP
     glib-2.0
     capi-ui-efl-util
     capi-system-info
-    security-privilege-manager
 )
 
 INCLUDE_DIRECTORIES(SYSTEM
index 4967110..8740123 100644 (file)
@@ -14,9 +14,9 @@
  *  limitations under the License
  */
 /**
- * @file        src/agent/notification-daemon/Service.cpp
- * @author      Zofia Abramowska <z.abramowska@samsung.com>
- * @brief       Declaration of Popupper class
+ * @file        Logic.cpp
+ * @author      Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief       Declaration of Logic class
  */
 
 #include "Logic.h"
 #include <exception/Exception.h>
 #include <exception/ErrnoException.h>
 #include <policy/Policy.h>
+#include <policy/PrivilegePolicy.h>
+
 #include "PolicyUpdater.h"
 #include "ServerCallbacks.h"
-#include "policy/PrivilegeInfo.h"
-
 
 namespace AskUser {
 
@@ -225,35 +225,8 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
     }
     ConnectionInfo &conn = it->second;
 
-    std::vector<Privacy> privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(conn.appId, privilege);
-    if (privacies.empty()) {
-        ALOGE("Privilege " << privilege << " doesn't map to any privacy");
-        m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
-        return;
-    }
-
-    std::vector<Policy> policies;
-
-    std::string removePrivacy = "removeme";
-    for (auto &privacy : privacies) {
-        std::string policy = calculatePolicyForPrivacy(conn.appId, privacy);
-        if (policy == "Allow") {
-            // Remove privacies which are already allowed - we don't need to spam user more with popups
-            privacy = removePrivacy;
-        }
-        if (policy.empty()) {
-            ALOGD("Application doesn't use privacy " << privacy);
-            continue;
-        }
-        policies.push_back(policy);
-    }
-
-    if (policies.empty()) {
-        ALOGD("Privilege " << privilege << " is not privacy for app : " << conn.appId);
-        m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_FOREVER);
-        return;
-    }
-    std::string policyLevel = getMinimumPolicy(policies);
+    PrivilegePolicy privPolicy(conn.appId, privilege);
+    auto policyLevel = privPolicy.calculatePolicy();
 
     ALOGD("Privilege policy level calculated to : " << policyLevel);
     if (policyLevel == "Allow") {
@@ -271,8 +244,13 @@ void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::
         return;
     }
 
-    auto removeIt = std::remove_if(privacies.begin(), privacies.end(), [&](const Privacy &privacy) {return privacy == removePrivacy;});
-    privacies.erase(removeIt, privacies.end());
+    auto privacies = privPolicy.getAskablePrivacies();
+    if (privacies.empty()) {
+        ALOGE("All privacies for privilege " << privilege
+              << " are already allowed");
+        m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
+        return;
+    }
 
     addEvent(fd, id, privacies);
     processEvents();