List policies: server side implementation 30/33930/38
authorKrzysztof Sasiak <k.sasiak@samsung.com>
Wed, 11 Feb 2015 11:37:05 +0000 (12:37 +0100)
committerRafal Krypa <r.krypa@samsung.com>
Mon, 2 Mar 2015 11:42:50 +0000 (12:42 +0100)
Change-Id: Ic771c46851a46847c007a06ecd65107465957bf8
Signed-off-by: Krzysztof Sasiak <k.sasiak@samsung.com>
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
src/common/cynara.cpp
src/common/include/cynara.h
src/common/include/service_impl.h
src/common/include/smack-labels.h
src/common/service_impl.cpp
src/common/smack-labels.cpp
src/server/service/include/service.h
src/server/service/service.cpp

index 80e5b88..6d19977 100644 (file)
@@ -488,7 +488,7 @@ int CynaraAdmin::convertToPolicyType(const std::string &policy, bool forceRefres
 
     return DescriptionToType.at(policy);
 }
-void CynaraAdmin::Check(const std::string &label, const std::string &privilege, const std::string &user,
+void CynaraAdmin::Check(const std::string &label, const std::string &user, const std::string &privilege,
     const std::string &bucket, int &result, std::string &resultExtra, const bool recursive)
 {
     char *resultExtraCstr = nullptr;
@@ -507,6 +507,28 @@ void CynaraAdmin::Check(const std::string &label, const std::string &privilege,
     }
 }
 
+int CynaraAdmin::GetPrivilegeManagerCurrLevel(const std::string &label, const std::string &user,
+        const std::string &privilege)
+{
+    int result;
+    std::string resultExtra;
+
+    Check(label, user, privilege, Buckets.at(Bucket::PRIVACY_MANAGER), result, resultExtra, true);
+
+    return result;
+}
+
+int CynaraAdmin::GetPrivilegeManagerMaxLevel(const std::string &label, const std::string &user,
+        const std::string &privilege)
+{
+    int result;
+    std::string resultExtra;
+
+    Check(label, user, privilege, Buckets.at(Bucket::MAIN), result, resultExtra, true);
+
+    return result;
+}
+
 Cynara::Cynara()
 {
     checkCynaraError(
index 659b2db..a75e414 100644 (file)
@@ -223,13 +223,40 @@ public:
      *        all buckets linked with bucket provided
      */
     void Check(const std::string &label,
-        const std::string &privilege,
         const std::string &user,
+        const std::string &privilege,
         const std::string &bucket,
         int &result,
         std::string &resultExtra,
         const bool recursive);
 
+    /**
+     * Get current policy level for privilege-manager functionality
+     * Returns current policy value for given application, user and privilege
+     * identifiers.
+     *
+     * @param label application Smack label
+     * @param user user identifier (uid)
+     * @param privilege privilege identifier
+     * @return current policy value
+     */
+    int GetPrivilegeManagerCurrLevel(const std::string &label, const std::string &user,
+        const std::string &privilege);
+
+    /**
+     * Get maximum policy level for privilege-manager functionality
+     * Returns maximum possible policy value for given application, user and privilege
+     * identifiers. The maximum limit is imposed by other policy settings that are
+     * currently in place.
+     *
+     * @param label application Smack label
+     * @param user user identifier (uid)
+     * @param privilege privilege identifier
+     * @return maximum policy value for PRIVACY_MANAGER bucket
+     */
+    int GetPrivilegeManagerMaxLevel(const std::string &label, const std::string &user,
+        const std::string &privilege);
+
 private:
     CynaraAdmin();
 
index e88951b..c7c2711 100644 (file)
@@ -113,7 +113,36 @@ int userDelete(uid_t uidDeleted, uid_t uid);
  *
  * @return API return code, as defined in protocols.h
  */
+
 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel);
+/**
+ * Fetch all configured privileges from user configurable bucket.
+ * Depending on forAdmin value: personal user policies or admin enforced
+ * policies are returned.
+ *
+ * @param[in] forAdmin determines if user is asking as ADMIN or not
+ * @param[in] filter filter for limiting the query
+ * @param[in] uid identifier of queried user
+ * @param[in] pid PID of requesting process
+ * @param[out] policyEntries vector of policy entries with result
+ *
+ * @return API return code, as defined in protocols.h
+ */
+int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries);
+
+/**
+ * Fetch all privileges for all apps installed for specific user.
+ *
+ * @param[in] forAdmin determines if user is asking as ADMIN or not
+ * @param[in] filter filter for limiting the query
+ * @param[in] uid identifier of queried user
+ * @param[in] pid PID of requesting process
+ * @param[out] policyEntries vector of policy entries with result
+ *
+ * @return API return code, as defined in protocols.h
+ */
+int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries);
+
 } /* namespace ServiceImpl */
 } /* namespace SecurityManager */
 
index e45b085..3089462 100644 (file)
@@ -47,6 +47,14 @@ bool setupPath(const std::string &pkgId, const std::string &path,
     app_install_path_type pathType);
 
 /**
+ * Generates application name for a label fetched from Cynara
+ *
+ * @param[in] label string to fetch application name for
+ * @return application name on success, empty string on error.
+*/
+std::string generateAppNameFromLabel(const std::string &label);
+
+/**
  * Generates label for an application with a specific application ID
  * read from @ref appId and assigns it to @ref label.
  *
index d32cdb5..6855337 100644 (file)
@@ -571,5 +571,232 @@ int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_
     return SECURITY_MANAGER_API_SUCCESS;
 }
 
+int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
+    const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
+{
+    try {
+        std::string uidStr = std::to_string(uid);
+        std::string pidStr = std::to_string(pid);
+
+        if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+            LogError("Not enough permission to call: " << __FUNCTION__);
+            return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+        };
+
+        LogDebug("Filter is: C: " << filter.appId
+                    << ", U: " << filter.user
+                    << ", P: " << filter.privilege
+                    << ", current: " << filter.currentLevel
+                    << ", max: " << filter.maxLevel
+                    );
+
+        std::vector<CynaraAdminPolicy> listOfPolicies;
+
+        //convert appId to smack label
+        std::string appLabel;
+        if (!filter.appId.compare(SECURITY_MANAGER_ANY))
+            appLabel = CYNARA_ADMIN_ANY;
+        else
+            generateAppLabel(filter.appId, appLabel);
+
+        std::string user = (!filter.user.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.user;
+        std::string privilege = (!filter.privilege.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.privilege;
+
+        LogDebug("App: " << filter.appId << ", Label: " << appLabel);
+
+        if (forAdmin) {
+            if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+                LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
+                return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+                };
+
+            //Fetch privileges from ADMIN bucket
+            CynaraAdmin::getInstance().ListPolicies(
+                CynaraAdmin::Buckets.at(Bucket::ADMIN),
+                appLabel,
+                user,
+                privilege,
+                listOfPolicies
+                );
+            LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
+        } else {
+            if (uidStr.compare(user)) {
+                if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+                    LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
+                    user = uidStr;
+                };
+            };
+            //Fetch privileges from PRIVACY_MANAGER bucket
+            CynaraAdmin::getInstance().ListPolicies(
+                CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
+                appLabel,
+                user,
+                privilege,
+                listOfPolicies
+                );
+            LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
+        };
+
+        for (const auto &policy : listOfPolicies) {
+            //ignore "jump to bucket" entries
+            if (policy.result ==  CYNARA_ADMIN_BUCKET)
+                continue;
+
+            policy_entry pe;
+
+            pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
+            pe.user =  strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
+            pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
+            pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
+
+            if (!forAdmin) {
+                // All policy entries in PRIVACY_MANAGER should be fully-qualified
+                pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+                    CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
+                        policy.client, policy.user, policy.privilege));
+            } else {
+                // Cannot reliably calculate maxLavel for policies from ADMIN bucket
+                pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
+            }
+
+
+            LogDebug(
+                "[policy_entry] app: " << pe.appId
+                << " user: " << pe.user
+                << " privilege: " << pe.privilege
+                << " current: " << pe.currentLevel
+                << " max: " << pe.maxLevel
+                );
+
+            policyEntries.push_back(pe);
+        };
+
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while listing Cynara rules: " << e.DumpToString());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation error while listing Cynara rules: " << e.what());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    }
+
+
+    return SECURITY_MANAGER_API_SUCCESS;
+}
+
+int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
+{
+    try {
+        std::string uidStr = std::to_string(uid);
+        std::string pidStr = std::to_string(pid);
+
+        if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+            LogWarning("Not enough permission to call: " << __FUNCTION__);
+            return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+        };
+
+        LogDebug("Filter is: C: " << filter.appId
+                    << ", U: " << filter.user
+                    << ", P: " << filter.privilege
+                    << ", current: " << filter.currentLevel
+                    << ", max: " << filter.maxLevel
+                    );
+
+        std::vector<uid_t> listOfUsers;
+
+        if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+            LogDebug("User is privileged");
+            if (filter.user.compare(SECURITY_MANAGER_ANY)) {
+                LogDebug("Limitting Cynara query to user: " << filter.user);
+                try {
+                    listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
+                } catch (std::invalid_argument &e) {
+                    LogError("Invalid UID: " << e.what());
+                };
+            } else
+                CynaraAdmin::getInstance().ListUsers(listOfUsers);
+        } else {
+            LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
+            LogDebug("Fetching personal policy for user: " << uid);
+            listOfUsers.push_back(uid);
+        };
+        LogDebug("Fetching policy for " << listOfUsers.size() << " users");
+
+        for (const uid_t &uid : listOfUsers) {
+            LogDebug("User: " << uid);
+            std::string userStr = std::to_string(uid);
+            std::vector<std::string> listOfApps;
+
+            if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
+                LogDebug("Limitting Cynara query to app: " << filter.appId);
+                listOfApps.push_back(filter.appId);
+            } else {
+                PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
+                LogDebug("Found apps: " << listOfApps.size());
+            };
+
+            for (const std::string &appId : listOfApps) {
+                LogDebug("App: " << appId);
+                std::string smackLabelForApp;
+                std::vector<std::string> listOfPrivileges;
+
+                generateAppLabel(appId, smackLabelForApp);
+                // FIXME: also fetch privileges of global applications
+                PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
+
+                if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
+                    LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
+                    // FIXME: this filtering should be already performed by method fetching the privileges
+                    if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
+                        filter.privilege) == listOfPrivileges.end()) {
+                        LogDebug("Application " << appId <<
+                            " doesn't have the filteres privilege " << filter.privilege);
+                        continue;
+                    }
+                    listOfPrivileges.clear();
+                    listOfPrivileges.push_back(filter.privilege);
+                }
+
+                LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
+
+                for (const std::string &privilege : listOfPrivileges) {
+                    LogDebug("Privilege: " << privilege);
+                    policy_entry pe;
+
+                    pe.appId = appId;
+                    pe.user = userStr;
+                    pe.privilege = privilege;
+
+                    pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+                        CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
+                            smackLabelForApp, userStr, privilege));
+
+                    pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+                        CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
+                            smackLabelForApp, userStr, privilege));
+
+                    LogDebug(
+                        "[policy_entry] app: " << pe.appId
+                        << " user: " << pe.user
+                        << " privilege: " << pe.privilege
+                        << " current: " << pe.currentLevel
+                        << " max: " << pe.maxLevel
+                        );
+
+                    policyEntries.push_back(pe);
+                };
+            };
+        };
+
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while listing Cynara rules: " << e.DumpToString());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation error while listing Cynara rules: " << e.what());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    }
+
+    return SECURITY_MANAGER_API_SUCCESS;
+}
+
 } /* namespace ServiceImpl */
 } /* namespace SecurityManager */
index 7b68a45..616dd43 100644 (file)
@@ -187,6 +187,12 @@ bool setupPath(const std::string &pkgId, const std::string &path,
     return labelDir(path, label, label_transmute, label_executables);
 }
 
+std::string generateAppNameFromLabel(const std::string &label)
+{
+    //TODO: Fix when a label generating mechanism is ready
+    return label;
+}
+
 bool generateAppLabel(const std::string &appId, std::string &label)
 {
     (void) appId;
index 3cc07c1..9d0a420 100644 (file)
@@ -94,7 +94,6 @@ private:
 
     void processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid);
 
-
     /**
      * Process policy update request
      *
@@ -105,6 +104,34 @@ private:
      * @param  smackLabel smack label of requesting app
      */
     void processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel);
+
+    /**
+     * List all privileges for specific user, placed in Cynara's PRIVACY_MANAGER
+     * or ADMIN's bucket - choice based on forAdmin parameter
+     *
+     * @param  buffer Raw received data buffer
+     * @param  send   Raw data buffer to be sent
+     * @param  uid    Identifier of the user who sent the request
+     * @param  pid    PID of the process which sent the request
+     * @param  smackLabel smack label of requesting app
+     * @param  forAdmin determines internal type of request
+     */
+    void processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel, bool forAdmin);
+
+    /**
+     * Get whole policy for specific user. Whole policy is a list of all apps,
+     * and their permissions (based on what they've stated in their manifests).
+     * If uid is unprivileged, then only privileges for the caller uid will be
+     * listed. If uid is privileged, then apps for all the users will be listed.
+     *
+     * @param  buffer Raw received data buffer
+     * @param  send     Raw data buffer to be sent
+     * @param  uid      Identifier of the user who sent the request
+     * @param  pid      PID of the process which sent the request
+     * @param  smackLabel smack label of requesting app
+     */
+    void processGetPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel);
+
 };
 
 } // namespace SecurityManager
index 14109c7..a710871 100644 (file)
@@ -130,6 +130,15 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                 case SecurityModuleCall::POLICY_UPDATE:
                     processPolicyUpdate(buffer, send, uid, pid, smackLabel);
                     break;
+                case SecurityModuleCall::GET_CONF_POLICY_ADMIN:
+                    processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, true);
+                    break;
+                case SecurityModuleCall::GET_CONF_POLICY_SELF:
+                    processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, false);
+                    break;
+                case SecurityModuleCall::GET_POLICY:
+                    processGetPolicy(buffer, send, uid, pid, smackLabel);
+                    break;
                 default:
                     LogError("Invalid call: " << call_type_int);
                     Throw(ServiceException::InvalidAction);
@@ -235,7 +244,6 @@ void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_
     Serialization::Serialize(send, ret);
 }
 
-
 void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel)
 {
     int ret;
@@ -247,4 +255,32 @@ void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, ui
     Serialization::Serialize(send, ret);
 }
 
+void Service::processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel, bool forAdmin)
+{
+    int ret;
+    policy_entry filter;
+    Deserialization::Deserialize(buffer, filter);
+    std::vector<policy_entry> policyEntries;
+    ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries);
+    Serialization::Serialize(send, ret);
+    Serialization::Serialize(send, static_cast<int>(policyEntries.size()));
+    for (const auto &policyEntry : policyEntries) {
+        Serialization::Serialize(send, policyEntry);
+    };
+}
+
+void Service::processGetPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+    int ret;
+    policy_entry filter;
+    Deserialization::Deserialize(buffer, filter);
+    std::vector<policy_entry> policyEntries;
+    ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries);
+    Serialization::Serialize(send, ret);
+    Serialization::Serialize(send, static_cast<int>(policyEntries.size()));
+    for (const auto &policyEntry : policyEntries) {
+        Serialization::Serialize(send, policyEntry);
+    };
+}
+
 } // namespace SecurityManager