Add security_manager_groups_for_uid() 63/76063/13
authorAleksander Zdyb <a.zdyb@samsung.com>
Wed, 22 Jun 2016 12:47:52 +0000 (14:47 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Mon, 22 Aug 2016 13:59:56 +0000 (15:59 +0200)
This function returns resource-related groups for
given user.

Change-Id: I8b4a2bf2c2e85769543929e0ff5f0247dd60137a

16 files changed:
CMakeLists.txt
db/CMakeLists.txt
packaging/security-manager.spec
policy/CMakeLists.txt
policy/security-manager-policy-reload.in [moved from policy/security-manager-policy-reload with 95% similarity]
src/client/client-security-manager.cpp
src/common/cynara.cpp
src/common/include/cynara.h
src/common/include/privilege_db.h
src/common/include/protocols.h
src/common/include/service_impl.h
src/common/privilege_db.cpp
src/common/service_impl.cpp
src/include/app-runtime.h
src/server/service/include/service.h
src/server/service/service.cpp

index ec5954f..82c73ca 100644 (file)
@@ -33,7 +33,28 @@ SET(LOCAL_STATE_DIR
     CACHE PATH
     "Modifiable single-machine data directory")
 
+SET(DATA_ROOT_DIR
+    "${CMAKE_INSTALL_FULL_DATAROOTDIR}"
+    CACHE PATH
+    "Read-only data root directory")
+
+SET(POLICY_DIR
+    "${DATA_ROOT_DIR}/security-manager/policy"
+    CACHE PATH
+    "Read-only data root directory")
+
 ADD_DEFINITIONS("-DLOCAL_STATE_DIR=\"${LOCAL_STATE_DIR}\"")
+ADD_DEFINITIONS("-DDATA_ROOT_DIR=\"${DATA_ROOT_DIR}\"")
+ADD_DEFINITIONS("-DPOLICY_DIR=\"${POLICY_DIR}\"")
+
+############################## file names #####################################
+
+SET(PRIVILEGE_GROUP_LIST_FILE
+    "privilege-group.list"
+    CACHE PATH
+    "File with mapping from privileges into groups")
+
+ADD_DEFINITIONS("-DPRIVILEGE_GROUP_LIST_FILE=\"${PRIVILEGE_GROUP_LIST_FILE}\"")
 
 ############################# compiler flags ##################################
 
index d2dbdcf..e1d8f57 100644 (file)
@@ -1,4 +1,4 @@
-SET(DB_SCRIPT_DIR "${SHARE_INSTALL_PREFIX}/${PROJECT_NAME}/db")
+SET(DB_SCRIPT_DIR "${DATA_ROOT_DIR}/${PROJECT_NAME}/db")
 SET(FOTA_DIR "${SYSCONF_INSTALL_DIR}/opt/upgrade")
 
 # Update scrpipts
index eaeb567..1a76783 100644 (file)
@@ -82,6 +82,7 @@ export LDFLAGS+="-Wl,--rpath=%{_libdir}"
         -DDB_INSTALL_DIR=%{TZ_SYS_DB} \
         -DLOCAL_STATE_DIR=%{TZ_SYS_VAR} \
         -DSYSTEMD_INSTALL_DIR=%{_unitdir} \
+        -DDATA_ROOT_DIR=%{_datadir} \
         -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:RELEASE} \
         -DCMAKE_VERBOSE_MAKEFILE=ON
 make %{?jobs:-j%jobs}
index fbc5c3e..8daa099 100644 (file)
@@ -1,7 +1,10 @@
 FILE(GLOB USERTYPE_POLICY_FILES usertype-*.profile)
-INSTALL(FILES ${USERTYPE_POLICY_FILES} DESTINATION ${SHARE_INSTALL_PREFIX}/security-manager/policy)
-INSTALL(FILES "app-rules-template.smack" DESTINATION ${SHARE_INSTALL_PREFIX}/security-manager/policy)
-INSTALL(FILES "pkg-rules-template.smack" DESTINATION ${SHARE_INSTALL_PREFIX}/security-manager/policy)
-INSTALL(FILES "author-rules-template.smack" DESTINATION ${SHARE_INSTALL_PREFIX}/security-manager/policy)
-INSTALL(FILES "privilege-group.list" DESTINATION ${SHARE_INSTALL_PREFIX}/security-manager/policy)
+
+CONFIGURE_FILE(security-manager-policy-reload.in security-manager-policy-reload @ONLY)
+
+INSTALL(FILES ${USERTYPE_POLICY_FILES} DESTINATION ${POLICY_DIR})
+INSTALL(FILES "app-rules-template.smack" DESTINATION ${POLICY_DIR})
+INSTALL(FILES "pkg-rules-template.smack" DESTINATION ${POLICY_DIR})
+INSTALL(FILES "author-rules-template.smack" DESTINATION ${POLICY_DIR})
+INSTALL(FILES "privilege-group.list" DESTINATION ${POLICY_DIR})
 INSTALL(PROGRAMS security-manager-policy-reload DESTINATION ${BIN_INSTALL_DIR})
similarity index 95%
rename from policy/security-manager-policy-reload
rename to policy/security-manager-policy-reload.in
index fec5318..40959cb 100755 (executable)
@@ -1,8 +1,8 @@
 #!/bin/sh -e
 
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
-POLICY_PATH=/usr/share/security-manager/policy
-PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/privilege-group.list
+POLICY_PATH=@POLICY_DIR@
+PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/@PRIVILEGE_GROUP_LIST_FILE@
 
 DB_FILE=`tzplatform-get TZ_SYS_DB | cut -d= -f2`/.security-manager.db
 
index e9dc7d7..f184e6d 100644 (file)
@@ -28,6 +28,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <functional>
+#include <fstream>
 #include <memory>
 #include <unordered_set>
 #include <utility>
@@ -1149,6 +1150,53 @@ void security_manager_policy_levels_free(char **levels, size_t levels_count)
     delete[] levels;
 }
 
+static void loadGroups(std::vector<std::string> &vgroups) {
+    static const int LINEMAX = 256;
+    char line[LINEMAX];
+    std::ifstream input(POLICY_DIR "/" PRIVILEGE_GROUP_LIST_FILE);
+
+    while(input.getline(line, LINEMAX)) {
+        if (line[0] == '#')
+            continue;
+        char *pos = strchr(line, ' ');
+        if (pos == NULL)
+            continue;
+        pos++;
+        vgroups.push_back(std::string(pos));
+    }
+}
+
+static int group_vector_to_array(const std::vector<std::string> &vgroups, char ***groups, size_t *groups_count)
+{
+    const auto vgroups_size = vgroups.size();
+
+    std::unique_ptr<char *[], std::function<void(char **)>> array(
+        static_cast<char **>(calloc(vgroups_size, sizeof(char *))),
+        std::bind(security_manager_groups_free, std::placeholders::_1, vgroups_size));
+
+    if (array == nullptr)
+        return SECURITY_MANAGER_ERROR_MEMORY;
+
+    for (size_t i = 0; i < vgroups_size; ++i) {
+        const auto &group = vgroups.at(i);
+
+        if (group.empty()) {
+            LogError("Unexpected empty group");
+            return SECURITY_MANAGER_ERROR_UNKNOWN;
+        }
+
+        array[i] = strdup(group.c_str());
+        if (array[i] == nullptr) {
+            return SECURITY_MANAGER_ERROR_MEMORY;
+        }
+    }
+
+    *groups_count = vgroups_size;
+    *groups = array.release();
+
+    return SECURITY_MANAGER_SUCCESS;
+}
+
 SECURITY_MANAGER_API
 int security_manager_groups_get(char ***groups, size_t *groups_count)
 {
@@ -1157,9 +1205,34 @@ int security_manager_groups_get(char ***groups, size_t *groups_count)
     if (!groups || !groups_count)
         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
     return try_catch([&]() -> int {
+        std::vector<std::string> vgroups;
+        loadGroups(vgroups);
+        return group_vector_to_array(vgroups, groups, groups_count);
+    });
+}
+
+SECURITY_MANAGER_API
+int security_manager_groups_get_for_user(uid_t uid, char ***groups, size_t *groups_count)
+{
+    using namespace SecurityManager;
+    if (!groups || !groups_count)
+        return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+    // Security manager does not manage platform system daemons
+    // This 5000 value is defined only in this document:
+    // https://wiki.tizen.org/wiki/Security/User_and_group_ID_assignment_policy
+    // TODO: Value 5000 should be defined in tizen-platform-config
+
+    if (uid < 5000) {
+        return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+    }
+
+    return try_catch([&]() -> int {
+        MessageBuffer send, recv;
 
         //put data into buffer
-        Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::GROUPS_GET));
+        Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::GROUPS_FOR_UID));
+        Serialization::Serialize(send, uid);
 
         //send buffer to server
         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
@@ -1170,39 +1243,14 @@ int security_manager_groups_get(char ***groups, size_t *groups_count)
 
         //receive response from server
         Deserialization::Deserialize(recv, retval);
-
         if (retval != SECURITY_MANAGER_SUCCESS) {
             return retval;
         }
 
         std::vector<std::string> vgroups;
         Deserialization::Deserialize(recv, vgroups);
-        const auto vgroups_size = vgroups.size();
-        LogInfo("Number of groups: " << vgroups_size);
-
-        auto array = makeUnique(static_cast<char **>(calloc(vgroups_size, sizeof(char *))),
-            std::bind(security_manager_groups_free, std::placeholders::_1, vgroups_size));
-
-        if (!array)
-            return SECURITY_MANAGER_ERROR_MEMORY;
 
-        for (size_t i = 0; i < vgroups_size; ++i) {
-            const auto &group = vgroups.at(i);
-
-            if (group.empty()) {
-                LogError("Unexpected empty group");
-                return SECURITY_MANAGER_ERROR_UNKNOWN;
-            }
-
-            array.get()[i] = strdup(group.c_str());
-            if (array.get()[i] == nullptr)
-                return SECURITY_MANAGER_ERROR_MEMORY;
-        }
-
-        *groups_count = vgroups_size;
-        *groups = array.release();
-
-        return SECURITY_MANAGER_SUCCESS;
+        return group_vector_to_array(vgroups, groups, groups_count);
     });
 }
 
index f66dd38..04cff83 100644 (file)
@@ -473,6 +473,37 @@ void CynaraAdmin::UserRemove(uid_t uid)
             CYNARA_ADMIN_ANY, user, CYNARA_ADMIN_ANY);
 }
 
+security_manager_user_type CynaraAdmin::GetUserType(uid_t uid)
+{
+    std::string uidStr = std::to_string(uid);
+    std::vector<CynaraAdminPolicy> tmpListOfUsers;
+    CynaraAdmin::getInstance().ListPolicies(
+            CynaraAdmin::Buckets.at(Bucket::MAIN),
+            CYNARA_ADMIN_WILDCARD,
+            uidStr,
+            CYNARA_ADMIN_WILDCARD,
+            tmpListOfUsers);
+
+    if (tmpListOfUsers.size() != 1) {
+        // < 1 -> user not found
+        // > 1 -> impossible
+        return SM_USER_TYPE_NONE;
+    }
+
+    auto metadata = tmpListOfUsers.at(0).result_extra;
+
+    if (metadata == Buckets.at(Bucket::USER_TYPE_NORMAL))
+        return SM_USER_TYPE_NORMAL;
+    else if (metadata == Buckets.at(Bucket::USER_TYPE_ADMIN))
+        return SM_USER_TYPE_ADMIN;
+    else if (metadata == Buckets.at(Bucket::USER_TYPE_GUEST))
+        return SM_USER_TYPE_GUEST;
+    else if (metadata == Buckets.at(Bucket::USER_TYPE_SYSTEM))
+        return SM_USER_TYPE_SYSTEM;
+    else    // improperly configured
+        return SM_USER_TYPE_NONE;
+};
+
 void CynaraAdmin::ListPolicies(
     const std::string &bucket,
     const std::string &label,
index c7c994e..ca8b4d6 100644 (file)
@@ -176,6 +176,16 @@ public:
     void UserRemove(uid_t uid);
 
     /**
+     * Returns user type of given uid
+     *
+     * @param[in] uid uid to check
+     *
+     * @return security_manager_user_type for given uid or SM_USER_TYPE_NONE if user not found
+     *
+     */
+    security_manager_user_type GetUserType(uid_t uid);
+
+    /**
      * List Cynara policies that match selected criteria in given bucket.
      *
      * @param bucketName name of the bucket to search policies in
index 3216401..5bc1519 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * security-manager, database access
  *
- * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -31,6 +31,7 @@
 
 #include <cstdio>
 #include <list>
+#include <utility>
 #include <map>
 #include <stdbool.h>
 #include <string>
@@ -121,7 +122,7 @@ private:
         { StmtType::EGetUserApps, "SELECT app_name FROM user_app_pkg_view WHERE uid=?" },
         { StmtType::EGetTizen2XPackages,  "SELECT DISTINCT pkg_name FROM user_app_pkg_view WHERE version LIKE '2.%%'" },
         { StmtType::EGetAppsInPkg, " SELECT app_name FROM user_app_pkg_view WHERE pkg_name = ?" },
-        { StmtType::EGetGroups, "SELECT DISTINCT group_name FROM privilege_group" },
+        { StmtType::EGetGroups, "SELECT DISTINCT group_name, privilege_name FROM privilege_group" },
         { StmtType::EGetPkgAuthorId, "SELECT author_id FROM pkg WHERE name = ? AND author_id IS NOT NULL"},
         { StmtType::EAuthorIdExists, "SELECT count(*) FROM author where author_id=?"},
         { StmtType::EGetAuthorIdByName, "SELECT author_id FROM author WHERE name=?"},
@@ -453,6 +454,16 @@ public:
      * @exception DB::SqlConnection::Exception::ConstraintError on constraint violation
      */
     void GetGroups(std::vector<std::string> &grp_names);
+
+    /**
+     * Retrieve vector of pairs with group_name (1st value) and privilege_name (2nd value)
+     *
+     * @param[out] privileges - list of privileges
+     * @exception DB::SqlConnection::Exception::InternalError on internal error
+     * @exception DB::SqlConnection::Exception::ConstraintError on constraint violation
+     */
+    void GetGroupsRelatedPrivileges(std::vector<std::pair<std::string, std::string>> &privileges);
+
 };
 
 } //namespace SecurityManager
index 1690f74..9493cf9 100644 (file)
@@ -85,6 +85,7 @@ enum class SecurityModuleCall
     GROUPS_GET,
     APP_HAS_PRIVILEGE,
     PATHS_REGISTER,
+    GROUPS_FOR_UID,
     NOOP = 0x90,
 };
 
index 2b0a6fa..82774ff 100644 (file)
@@ -210,6 +210,17 @@ public:
     int policyGetGroups(std::vector<std::string> &groups);
 
     /**
+     * Receive groups connected with uid and add them
+     * to the vector.
+     *
+     * @param[in] uid to return the groups for
+     * @param[out] groups vector with groups
+     *
+     * @return API return code, as defined in protocols.h
+     */
+    int policyGroupsForUid(uid_t uid, std::vector<std::string> &groups);
+
+    /**
      * Process checking application's privilege access based on app_name
      *
      * @param[in]  appName application identifier
index 1c225e1..3b70cac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * security-manager, database access
  *
- * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -29,6 +29,7 @@
 
 #include <cstdio>
 #include <list>
+#include <utility>
 #include <string>
 #include <iostream>
 
@@ -497,4 +498,18 @@ void PrivilegeDb::GetGroups(std::vector<std::string> &groups)
     });
 }
 
+void PrivilegeDb::GetGroupsRelatedPrivileges(std::vector<std::pair<std::string, std::string>> &privileges)
+{
+    try_catch<void>([&] {
+        auto command = getStatement(StmtType::EGetGroups);
+
+        while (command->Step()) {
+            const auto &groupName = command->GetColumnString(0);
+            const auto &privName = command->GetColumnString(1);
+            LogDebug("Privilege " << privName << " Group " << groupName);
+            privileges.emplace_back(std::make_pair(groupName, privName));
+        };
+    });
+}
+
 } //namespace SecurityManager
index 5268730..25852bf 100644 (file)
@@ -1218,6 +1218,60 @@ int ServiceImpl::policyGetGroups(std::vector<std::string> &groups)
     return ret;
 }
 
+int ServiceImpl::policyGroupsForUid(uid_t uid, std::vector<std::string> &groups)
+{
+    int ret = SECURITY_MANAGER_SUCCESS;
+
+    try {
+        auto userType = CynaraAdmin::getInstance().GetUserType(uid);
+
+        if (userType == SM_USER_TYPE_NONE) {
+            return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+        }
+
+        auto uidStr = std::to_string(uid);
+        int result;
+        std::string resultExtra;
+        std::string bucket;
+
+        switch (userType) {
+            case SM_USER_TYPE_NORMAL:
+                bucket = CynaraAdmin::Buckets.at(Bucket::USER_TYPE_NORMAL);
+                break;
+            case SM_USER_TYPE_ADMIN:
+                bucket = CynaraAdmin::Buckets.at(Bucket::USER_TYPE_ADMIN);
+                break;
+            case SM_USER_TYPE_GUEST:
+                bucket = CynaraAdmin::Buckets.at(Bucket::USER_TYPE_GUEST);
+                break;
+            case SM_USER_TYPE_SYSTEM:
+                bucket = CynaraAdmin::Buckets.at(Bucket::USER_TYPE_SYSTEM);
+                break;
+            default:
+                // Improperly configured
+                return SECURITY_MANAGER_ERROR_UNKNOWN;
+        }
+
+        std::vector<std::pair<std::string, std::string>> group2privVector;
+        PrivilegeDb::getInstance().GetGroupsRelatedPrivileges(group2privVector);
+
+        for (const auto &g2p : group2privVector) {
+            CynaraAdmin::getInstance().Check(CYNARA_ADMIN_ANY, uidStr, g2p.second,
+                                             bucket, result, resultExtra, true);
+            if (result == CYNARA_ADMIN_ALLOW)
+                groups.push_back(g2p.first);
+        }
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while getting user type from Cynara: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const PrivilegeDb::Exception::Base &e) {
+        LogError("Error while getting groups from database: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    }
+
+    return ret;
+}
+
 int ServiceImpl::appHasPrivilege(
         std::string appName,
         std::string privilege,
index 8ace21c..3303523 100644 (file)
@@ -102,6 +102,20 @@ int security_manager_prepare_app(const char *app_id);
 int security_manager_groups_get(char ***groups, size_t *groups_count);
 
 /**
+ * This function returns array of groups bound to privileges, the process
+ * run by particular user should get.
+ *
+ * Caller needs to free memory allocated for the list using
+ * security_manager_groups_free().
+ *
+ * @param[in] uid uid for user running the process
+ * @param[out] groups pointer to array of group names
+ * @param[out] groups_count number of strings in levels array
+ * @return API return code or error code.
+ */
+int security_manager_groups_get_for_user(uid_t uid, char ***groups, size_t *groups_count);
+
+/**
  * This function frees memory allocated by security_manager_groups_get()
  * function.
  *
index b7df7f3..8330f5b 100644 (file)
@@ -147,6 +147,13 @@ private:
     void processGroupsGet(MessageBuffer &send);
 
     /**
+     * Process getting groups bound with privileges for given uid
+     *
+     * @param  send   Raw data buffer to be sent
+     */
+    void processGroupsForUid(MessageBuffer &recv, MessageBuffer &send);
+
+    /**
      * Process checking application's privilege access based on app_id
      *
      * @param  recv   Raw received data buffer
index 270a37a..394bf42 100644 (file)
@@ -126,6 +126,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                     LogDebug("call_type: SecurityModuleCall::GROUPS_GET");
                     processGroupsGet(send);
                     break;
+                case SecurityModuleCall::GROUPS_FOR_UID:
+                    processGroupsForUid(buffer, send);
+                    break;
                 case SecurityModuleCall::APP_HAS_PRIVILEGE:
                     LogDebug("call_type: SecurityModuleCall::APP_HAS_PRIVILEGE");
                     processAppHasPrivilege(buffer, send);
@@ -323,6 +326,21 @@ void Service::processGroupsGet(MessageBuffer &send)
     }
 }
 
+void Service::processGroupsForUid(MessageBuffer &recv, MessageBuffer &send)
+{
+    uid_t uid;
+    std::vector<std::string> groups;
+
+    Deserialization::Deserialize(recv, uid);
+
+    int ret = serviceImpl.policyGroupsForUid(uid, groups);
+
+    Serialization::Serialize(send, ret);
+    if (ret == SECURITY_MANAGER_SUCCESS) {
+        Serialization::Serialize(send, groups);
+    }
+}
+
 void Service::processAppHasPrivilege(MessageBuffer &recv, MessageBuffer &send)
 {
     std::string appName;