Policy update: server side implementation 64/32764/31
authorKrzysztof Sasiak <k.sasiak@samsung.com>
Tue, 23 Dec 2014 14:53:09 +0000 (15:53 +0100)
committerRafal Krypa <r.krypa@samsung.com>
Tue, 24 Feb 2015 17:18:39 +0000 (18:18 +0100)
Change-Id: I920cc940b541c21607dd836d1f426c1f622ffbb2
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/service_impl.cpp
src/server/service/include/service.h
src/server/service/service.cpp

index 156ff26..6620708 100644 (file)
@@ -175,6 +175,26 @@ CynaraAdminPolicy::CynaraAdminPolicy(CynaraAdminPolicy &&that)
     that.result_extra = nullptr;
 }
 
+CynaraAdminPolicy& CynaraAdminPolicy::operator=(CynaraAdminPolicy &&that)
+{
+    if (this != &that) {
+        bucket = that.bucket;
+        client = that.client;
+        user = that.user;
+        privilege = that.privilege;
+        result_extra = that.result_extra;
+        result = that.result;
+
+        that.bucket = nullptr;
+        that.client = nullptr;
+        that.user = nullptr;
+        that.privilege = nullptr;
+        that.result_extra = nullptr;
+    };
+
+    return *this;
+}
+
 CynaraAdminPolicy::~CynaraAdminPolicy()
 {
     free(this->bucket);
index 1f37f96..5ac9e42 100644 (file)
@@ -80,6 +80,7 @@ struct CynaraAdminPolicy : cynara_admin_policy
 
     /* Move constructor is the way to go. */
     CynaraAdminPolicy(CynaraAdminPolicy &&that);
+    CynaraAdminPolicy& operator=(CynaraAdminPolicy &&that);
 
     ~CynaraAdminPolicy();
 };
index d281bc8..e88951b 100644 (file)
@@ -102,6 +102,18 @@ int userAdd(uid_t uidAdded, int userType, uid_t uid);
  */
 int userDelete(uid_t uidDeleted, uid_t uid);
 
+/**
+ * Update policy in Cynara - proper privilege: http://tizen.org/privilege/systemsettings.admin
+ * is needed for this to succeed
+ *
+ * @param[in] policyEntries vector of policy chunks with instructions
+ * @param[in] uid identifier of requesting user
+ * @param[in] pid PID of requesting process
+ * @param[in] smackLabel smack label of requesting app
+ *
+ * @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);
 } /* namespace ServiceImpl */
 } /* namespace SecurityManager */
 
index 824b1a9..d32cdb5 100644 (file)
@@ -20,6 +20,7 @@
  * @author      Michal Witanowski <m.witanowski@samsung.com>
  * @author      Jacek Bukarewicz <j.bukarewicz@samsung.com>
  * @author      Rafal Krypa <r.krypa@samsung.com>
+ * @author      Krzysztof Sasiak <k.sasiak@samsung.com>
  * @brief       Implementation of the service methods
  */
 
 #include "cynara.h"
 #include "smack-rules.h"
 #include "smack-labels.h"
+#include "security-manager.h"
 
 #include "service_impl.h"
 
 namespace SecurityManager {
 namespace ServiceImpl {
 
+static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
+static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
+
+namespace {
+
+static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
+{
+    LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
+    LogDebug("[policy_entry] app: " << policyEntry.appId
+            << " user: " << policyEntry.user
+            << " privilege: " << policyEntry.privilege
+            << " current: " << policyEntry.currentLevel
+            << " max: " << policyEntry.maxLevel);
+    //automagically fill missing fields:
+    if (policyEntry.user.empty()) {
+        policyEntry.user = uidStr;
+    };
+
+    std::string client;
+    int level;
+
+    if (policyEntry.currentLevel.empty()) { //for admin
+        if (policyEntry.appId.empty()
+            || policyEntry.privilege.empty()) {
+            LogError("Bad admin update request");
+            return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+        };
+
+        if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
+            level = CYNARA_ADMIN_DELETE;
+        } else {
+            try {
+                level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
+            } catch (const std::out_of_range& e) {
+                LogError("policy max level cannot be: " << policyEntry.maxLevel);
+                return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
+            };
+        };
+        forAdmin = true;
+
+    } else if (policyEntry.maxLevel.empty()) { //for self
+        if (policyEntry.user.compare(uidStr)
+            || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
+            || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
+            || policyEntry.appId.empty()
+            || policyEntry.privilege.empty()) {
+            LogError("Bad privacy manager update request");
+            return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+        };
+
+        if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
+            level = CYNARA_ADMIN_DELETE;
+        } else {
+            try {
+                level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
+            } catch (const std::out_of_range& e) {
+                LogError("policy current level cannot be: " << policyEntry.currentLevel);
+                return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
+            };
+        };
+        forAdmin = false;
+
+    } else { //neither => bad request
+        return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+    };
+
+    if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
+        policyEntry.user = CYNARA_ADMIN_WILDCARD;
+    if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
+        policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
+    if (policyEntry.appId.compare(SECURITY_MANAGER_ANY))
+        generateAppLabel(policyEntry.appId, client);
+    else
+        client = CYNARA_ADMIN_WILDCARD;
+
+    cyap = std::move(CynaraAdminPolicy(
+        client,
+        policyEntry.user,
+        policyEntry.privilege,
+        level,
+        (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
+
+    LogDebug("Policy update request authenticated and validated successfully");
+    return SECURITY_MANAGER_API_SUCCESS;
+}
+} // end of anonymous namespace
+
 static uid_t getGlobalUserId(void)
 {
     static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
@@ -422,5 +511,65 @@ int userDelete(uid_t uidDeleted, uid_t uid)
     return ret;
 }
 
+int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+    enum {
+        NOT_CHECKED,
+        IS_NOT_ADMIN,
+        IS_ADMIN
+    }  isAdmin = NOT_CHECKED;
+
+    try {
+        std::string uidStr = std::to_string(uid);
+        std::string pidStr = std::to_string(pid);
+
+        if (policyEntries.size() == 0) {
+            LogError("Validation failed: policy update request is empty");
+            return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+        };
+
+        if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+            LogError("Not enough permission to call: " << __FUNCTION__);
+            return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+        };
+
+        std::vector<CynaraAdminPolicy> validatedPolicies;
+
+        for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
+            bool forAdmin = false;
+            CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
+            int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
+
+            if (forAdmin && (isAdmin == NOT_CHECKED)) {
+                isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
+            };
+
+            if (ret == SECURITY_MANAGER_API_SUCCESS) {
+                if (!forAdmin
+                    || (forAdmin && (isAdmin == IS_ADMIN))) {
+                    validatedPolicies.push_back(std::move(cyap));
+                } else {
+                    LogError("Not enough privilege to enforce admin policy");
+                    return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+                };
+
+            } else
+                return ret;
+        };
+
+            // Apply updates
+        CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
+
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while updating Cynara rules: " << e.DumpToString());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation error while updating Cynara rules: " << e.what());
+        return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+    }
+
+    return SECURITY_MANAGER_API_SUCCESS;
+}
+
 } /* namespace ServiceImpl */
 } /* namespace SecurityManager */
index f7b8d21..3cc07c1 100644 (file)
@@ -94,6 +94,17 @@ private:
 
     void processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid);
 
+
+    /**
+     * Process policy update request
+     *
+     * @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 processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel);
 };
 
 } // namespace SecurityManager
index 8a20ca4..14109c7 100644 (file)
@@ -127,6 +127,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                 case SecurityModuleCall::USER_DELETE:
                     processUserDelete(buffer, send, uid);
                     break;
+                case SecurityModuleCall::POLICY_UPDATE:
+                    processPolicyUpdate(buffer, send, uid, pid, smackLabel);
+                    break;
                 default:
                     LogError("Invalid call: " << call_type_int);
                     Throw(ServiceException::InvalidAction);
@@ -233,4 +236,15 @@ void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_
 }
 
 
+void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+    int ret;
+    std::vector<policy_entry> policyEntries;
+
+    Deserialization::Deserialize(buffer, policyEntries);
+
+    ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel);
+    Serialization::Serialize(send, ret);
+}
+
 } // namespace SecurityManager