Optimize group processing performance 86/137886/2 accepted/tizen/3.0/common/20170714.175003 accepted/tizen/3.0/ivi/20170714.074157 accepted/tizen/3.0/mobile/20170714.074106 accepted/tizen/3.0/tv/20170714.074120 accepted/tizen/3.0/wearable/20170714.074132 submit/tizen_3.0/20170711.023638 submit/tizen_3.0/20170712.095854 submit/tizen_3.0/20170714.011431
authorRafal Krypa <r.krypa@samsung.com>
Fri, 7 Jul 2017 16:16:16 +0000 (18:16 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Mon, 10 Jul 2017 07:50:12 +0000 (09:50 +0200)
- Map group names to gids during server startup.
- Return gids instead of group names to client.
- Modify API used by NSS plugin to return gids and update the plugin.
- Cache privilege->gid mapping and privilege related gids on server side.

Change-Id: I30480565495e9591d893279f2df622fa21b6e1b9

16 files changed:
src/client/client-security-manager.cpp
src/common/CMakeLists.txt
src/common/group2gid.cpp [new file with mode: 0644]
src/common/include/group2gid.h [new file with mode: 0644]
src/common/include/privilege-gids.h [new file with mode: 0644]
src/common/include/privilege_db.h
src/common/include/service_impl.h
src/common/include/utils.h
src/common/privilege-gids.cpp [new file with mode: 0644]
src/common/privilege_db.cpp
src/common/service_impl.cpp
src/include/app-runtime.h
src/nss/CMakeLists.txt
src/nss/nss_securitymanager.cpp
src/server/service/service.cpp
test/test_privilege_db_privilege.cpp

index e838530e5c78349c44bc68b5a91df45040c72aac..a643186f1c37cc350fee8a13f631bf2c511442a6 100644 (file)
@@ -57,6 +57,7 @@
 #include <service_impl.h>
 #include <check-proper-drop.h>
 #include <utils.h>
+#include <group2gid.h>
 
 #include <security-manager.h>
 #include <client-offline.h>
@@ -419,22 +420,6 @@ static int setProcessGroups(const std::vector<gid_t> &groups)
     return SECURITY_MANAGER_SUCCESS;
 }
 
-static int groupNamesToGids(const std::vector<std::string> &groupNames,
-    std::vector<gid_t> &groups)
-{
-    groups.reserve(groupNames.size());
-    for (const auto &groupName : groupNames) {
-        struct group *grp = getgrnam(groupName.c_str());
-        if (grp == nullptr) {
-            LogError("No such group: " << groupName);
-            return SECURITY_MANAGER_ERROR_UNKNOWN;
-        }
-        groups.push_back(grp->gr_gid);
-    }
-
-    return SECURITY_MANAGER_SUCCESS;
-}
-
 static int getPrivilegedGroups(std::vector<gid_t> &groups)
 {
     ClientRequest request(SecurityModuleCall::GROUPS_GET);
@@ -443,9 +428,8 @@ static int getPrivilegedGroups(std::vector<gid_t> &groups)
         return request.getStatus();
     }
 
-    std::vector<std::string> groupNames;
-    request.recv(groupNames);
-    return groupNamesToGids(groupNames, groups);
+    request.recv(groups);
+    return SECURITY_MANAGER_SUCCESS;
 }
 
 static int getAppGroups(const std::string appName, std::vector<gid_t> &groups)
@@ -456,9 +440,8 @@ static int getAppGroups(const std::string appName, std::vector<gid_t> &groups)
         return request.getStatus();
     }
 
-    std::vector<std::string> groupNames;
-    request.recv(groupNames);
-    return groupNamesToGids(groupNames, groups);
+    request.recv(groups);
+    return SECURITY_MANAGER_SUCCESS;
 }
 
 namespace Syscall {
@@ -1127,11 +1110,13 @@ void security_manager_policy_levels_free(char **levels, size_t levels_count)
     delete[] levels;
 }
 
-static void loadGroups(std::vector<std::string> &vgroups) {
+static void loadGroups(std::vector<gid_t> &vgroups) {
     static const int LINEMAX = 256;
     char line[LINEMAX];
     std::ifstream input(POLICY_DIR "/" PRIVILEGE_GROUP_LIST_FILE);
 
+    Group2Gid g2g;
+
     while(input.getline(line, LINEMAX)) {
         if (line[0] == '#')
             continue;
@@ -1139,56 +1124,38 @@ static void loadGroups(std::vector<std::string> &vgroups) {
         if (pos == NULL)
             continue;
         pos++;
-        vgroups.push_back(std::string(pos));
+        vgroups.push_back(g2g.get(std::string(pos)));
     }
 }
 
-static int group_vector_to_array(const std::vector<std::string> &vgroups, char ***groups, size_t *groups_count)
+static int group_vector_to_array(const std::vector<gid_t> &vgroups, gid_t **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)
+    size_t size = vgroups.size() * sizeof(gid_t);
+    *groups = static_cast<gid_t*>(malloc(size));
+    if (*groups == 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();
+    *groups_count = vgroups.size();
+    memcpy(*groups, vgroups.data(), size);
 
     return SECURITY_MANAGER_SUCCESS;
 }
 
 SECURITY_MANAGER_API
-int security_manager_groups_get(char ***groups, size_t *groups_count)
+int security_manager_groups_get(gid_t **groups, size_t *groups_count)
 {
     using namespace SecurityManager;
     if (!groups || !groups_count)
         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
     return try_catch([&]() -> int {
-        std::vector<std::string> vgroups;
+        std::vector<gid_t> 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)
+int security_manager_groups_get_for_user(uid_t uid, gid_t **groups, size_t *groups_count)
 {
     using namespace SecurityManager;
     if (!groups || !groups_count)
@@ -1208,25 +1175,13 @@ int security_manager_groups_get_for_user(uid_t uid, char ***groups, size_t *grou
         if (request.send(uid).failed())
             return request.getStatus();
 
-        std::vector<std::string> vgroups;
+        std::vector<gid_t> vgroups;
         request.recv(vgroups);
 
         return group_vector_to_array(vgroups, groups, groups_count);
     });
 }
 
-SECURITY_MANAGER_API
-void security_manager_groups_free(char **groups, size_t groups_count)
-{
-    if (groups == nullptr)
-        return;
-
-    for (size_t i = 0; i < groups_count; i++)
-        free(groups[i]);
-
-    free(groups);
-}
-
 static lib_retcode get_app_and_pkg_id_from_smack_label(
         const std::string &label,
         char **pkg_name,
index 9fde0ba6e892c48fe39133100d4427ed8ba49430..d9be6b59711eae26e5dc1c25f2fc6f106cd08c6a 100644 (file)
@@ -62,6 +62,8 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/service_impl.cpp
     ${COMMON_PATH}/tzplatform-config.cpp
     ${COMMON_PATH}/privilege-info.cpp
+    ${COMMON_PATH}/privilege-gids.cpp
+    ${COMMON_PATH}/group2gid.cpp
     )
 
 IF(DPL_WITH_DLOG)
diff --git a/src/common/group2gid.cpp b/src/common/group2gid.cpp
new file mode 100644 (file)
index 0000000..20e9b1f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2017 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       group2gid.cpp
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#include "group2gid.h"
+
+#include <grp.h>
+
+namespace SecurityManager {
+
+namespace {
+
+struct GrEntGuard
+{
+    ~GrEntGuard() {
+        endgrent();
+    }
+};
+
+} // end of anonymous namespace
+
+Group2Gid::Group2Gid()
+{
+    GrEntGuard guard;
+
+    group* gr = nullptr;
+    for (;;) {
+        gr = getgrent();
+        if (!gr)
+            break;
+
+        m_group2gid[gr->gr_name] = gr->gr_gid;
+    }
+}
+
+gid_t Group2Gid::get(const std::string& group) const
+{
+    return m_group2gid.at(group);
+}
+
+} /* namespace SecurityManager */
+
diff --git a/src/common/include/group2gid.h b/src/common/include/group2gid.h
new file mode 100644 (file)
index 0000000..a5d5ede
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2017 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       group2gid.h
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <string>
+#include <unordered_map>
+
+namespace SecurityManager
+{
+
+class Group2Gid
+{
+public:
+    Group2Gid();
+
+    gid_t get(const std::string& group) const;
+private:
+    std::unordered_map<std::string, gid_t> m_group2gid;
+};
+
+} /* namespace SecurityManager */
+
+
diff --git a/src/common/include/privilege-gids.h b/src/common/include/privilege-gids.h
new file mode 100644 (file)
index 0000000..d4c8988
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2017 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       privilege-gids.h
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <unordered_map>
+
+namespace SecurityManager
+{
+
+class PrivilegeGids
+{
+public:
+    typedef std::vector<std::pair<std::string, std::string>> GroupPrivileges;
+
+    void init(const GroupPrivileges& group_privs);
+
+    // get gids by privilege
+    const std::vector<gid_t>& getGids(const std::string& privilege) const;
+    // get all gids
+    const std::vector<gid_t>& getGids() const;
+    // get all privileges
+    const std::vector<std::string>& getPrivileges() const;
+
+private:
+    std::unordered_map<std::string, std::vector<gid_t>> m_priv2gids;
+    std::vector<gid_t> m_gids;
+    std::vector<std::string> m_privileges;
+};
+
+} /* namespace SecurityManager */
index 1661b5ce7c3c83e896e186d8efca7f7157f56618..57c306c28f49cafe38b1c4e26ddb27b8ec949324 100644 (file)
@@ -66,12 +66,10 @@ enum class StmtType {
     ESquashSharing,
     EClearSharing,
     EClearPrivatePaths,
-    EGetPrivilegeGroups,
     EGetUserApps,
     EGetUserPkgs,
     EGetAllPackages,
     EGetAppsInPkg,
-    EGetGroups,
     EGetGroupsRelatedPrivileges,
     EGetPkgAuthorId,
     EAuthorIdExists,
@@ -120,12 +118,10 @@ private:
         { StmtType::ESquashSharing, "UPDATE app_private_sharing_view SET counter = 1 WHERE target_app_name = ? AND path = ?"},
         { StmtType::EClearSharing, "DELETE FROM app_private_sharing;"},
         { StmtType::EClearPrivatePaths, "DELETE FROM shared_path;"},
-        { StmtType::EGetPrivilegeGroups, " SELECT group_name FROM privilege_group WHERE privilege_name = ?" },
         { StmtType::EGetUserApps, "SELECT app_name FROM user_app_pkg_view WHERE uid=?" },
         { StmtType::EGetUserPkgs, "SELECT DISTINCT pkg_name FROM user_app_pkg_view WHERE uid=?" },
         { StmtType::EGetAllPackages,  "SELECT DISTINCT pkg_name FROM user_app_pkg_view" },
         { StmtType::EGetAppsInPkg, " SELECT app_name FROM user_app_pkg_view WHERE pkg_name = ?" },
-        { StmtType::EGetGroups, "SELECT DISTINCT group_name FROM privilege_group" },
         { StmtType::EGetGroupsRelatedPrivileges, "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=?"},
@@ -398,17 +394,6 @@ public:
      */
     void ClearPrivateSharing();
 
-    /**
-     * Retrieve list of group ids assigned to a privilege
-     *
-     * @param privilege - privilege identifier
-     * @param[out] grp_names - list of group names assigned to the privilege
-     * @exception PrivilegeDb::Exception::InternalError on internal error
-     * @exception PrivilegeDb::Exception::ConstraintError on constraint violation
-     */
-    void GetPrivilegeGroups(const std::string &privilege,
-        std::vector<std::string> &grp_names);
-
     /**
      * Retrieve list of apps assigned to user
      *
@@ -474,15 +459,6 @@ public:
      */
     void GetAuthorIdByName(const std::string &authorName, int &authorId);
 
-    /**
-     * Retrieve list of resource groups
-     *
-     * @param[out] grp_names - list of group names
-     * @exception PrivilegeDb::Exception::InternalError on internal error
-     * @exception PrivilegeDb::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)
      *
index bc75e50c6518f5be44117b76406b50dafb15d723..153f13ac95a0b9e23ce34d3be9d7fd394510504b 100644 (file)
@@ -34,6 +34,7 @@
 #include "smack-rules.h"
 #include "protocols.h"
 #include "privilege_db.h"
+#include "privilege-gids.h"
 
 namespace SecurityManager {
 
@@ -87,7 +88,7 @@ public:
     * @return API return code, as defined in protocols.h
     */
     int getAppGroups(const Credentials &creds, const std::string &appName,
-        std::vector<std::string> &groups);
+        std::vector<gid_t> &groups);
 
     /**
     * Process user adding request.
@@ -161,7 +162,7 @@ public:
      *
      * @return API return code, as defined in protocols.h
      */
-    int policyGetGroups(std::vector<std::string> &groups);
+    int policyGetGroups(std::vector<gid_t> &groups);
 
     /**
      * Receive groups connected with uid and add them
@@ -172,7 +173,7 @@ public:
      *
      * @return API return code, as defined in protocols.h
      */
-    int policyGroupsForUid(uid_t uid, std::vector<std::string> &groups);
+    int policyGroupsForUid(uid_t uid, std::vector<gid_t> &groups);
 
     /**
      * Process checking application's privilege access based on app_name
@@ -310,6 +311,7 @@ private:
     Cynara m_cynara;
     PrivilegeDb m_priviligeDb;
     CynaraAdmin m_cynaraAdmin;
+    PrivilegeGids m_privilegeGids;
 };
 
 } /* namespace SecurityManager */
index 9367d8697f2052d15b2ee363497b56c5b25af2fb..ff59af48ef1047440b245a95d74315606b31fa52 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <functional>
 #include <memory>
+#include <vector>
+#include <algorithm>
 
 namespace SecurityManager {
 
@@ -50,4 +52,12 @@ std::unique_ptr<T> makeUnique(size_t size)
     return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]);
 }
 
+
+template <typename T>
+static void vectorRemoveDuplicates(std::vector<T> &vec)
+{
+    std::sort(vec.begin(), vec.end());
+    vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
+}
+
 } /* namespace SecurityManager */
diff --git a/src/common/privilege-gids.cpp b/src/common/privilege-gids.cpp
new file mode 100644 (file)
index 0000000..6a2c170
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (c) 2017 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       privilege-gids.cpp
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#include "privilege-gids.h"
+
+#include <dpl/log/log.h>
+
+#include "utils.h"
+#include "group2gid.h"
+
+namespace SecurityManager {
+
+void PrivilegeGids::init(const GroupPrivileges &group_privs)
+{
+    m_priv2gids.clear();
+    m_gids.clear();
+
+    Group2Gid g2g;
+
+    // create privilege -> gids mapping & gather all privilege related gids
+    for (auto &group_priv : group_privs) {
+        gid_t g = g2g.get(group_priv.first);
+        LogDebug("group " << group_priv.first << "(" << g << ") privilege " << group_priv.second);
+        m_gids.push_back(g);
+        m_privileges.push_back(group_priv.second);
+        m_priv2gids[group_priv.second].push_back(g);
+    }
+
+    // remove duplicates
+    vectorRemoveDuplicates(m_gids);
+    vectorRemoveDuplicates(m_privileges);
+}
+
+const std::vector<gid_t>& PrivilegeGids::getGids(const std::string &privilege) const
+{
+    static std::vector<gid_t> empty;
+    const auto it = m_priv2gids.find(privilege);
+    if (it == m_priv2gids.end())
+        return empty;
+
+    return it->second;
+}
+
+const std::vector<gid_t>& PrivilegeGids::getGids() const
+{
+    return m_gids;
+}
+
+const std::vector<std::string>& PrivilegeGids::getPrivileges() const
+{
+    return m_privileges;
+}
+
+} /* namespace SecurityManager */
index 56173018f3ee5e97adabbc5fbb1b8801df75391e..42e1c060dcb6bae2d60283974871c5098275f708 100644 (file)
@@ -380,21 +380,6 @@ void PrivilegeDb::ClearPrivateSharing() {
     });
 }
 
-void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege,
-        std::vector<std::string> &groups)
-{
-   try_catch<void>([&] {
-        auto command = getStatement(StmtType::EGetPrivilegeGroups);
-        command->BindString(1, privilege);
-
-        while (command->Step()) {
-            std::string groupName = command->GetColumnString(0);
-            LogDebug("Privilege " << privilege << " gives access to group: " << groupName);
-            groups.push_back(groupName);
-        };
-    });
-}
-
 void PrivilegeDb::GetUserApps(uid_t uid, std::vector<std::string> &apps)
 {
    try_catch<void>([&] {
@@ -501,19 +486,6 @@ bool PrivilegeDb::AuthorIdExists(int authorId)
     });
 }
 
-void PrivilegeDb::GetGroups(std::vector<std::string> &groups)
-{
-   try_catch<void>([&] {
-        auto command = getStatement(StmtType::EGetGroups);
-
-        while (command->Step()) {
-            std::string groupName = command->GetColumnString(0);
-            LogDebug("Group " << groupName);
-            groups.push_back(groupName);
-        };
-    });
-}
-
 void PrivilegeDb::GetGroupsRelatedPrivileges(std::vector<std::pair<std::string, std::string>> &privileges)
 {
     try_catch<void>([&] {
index bec0060564a0fcce32e8fbdba05e6b8da0d81052..20c1f4dbbaaa11374de5121ea165ad0664df51a4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -25,7 +25,6 @@
  */
 
 #include <fcntl.h>
-#include <grp.h>
 #include <linux/xattr.h>
 #include <limits.h>
 #include <pwd.h>
@@ -99,6 +98,9 @@ private:
 
 ServiceImpl::ServiceImpl()
 {
+    PrivilegeGids::GroupPrivileges group_privileges;
+    m_priviligeDb.GetGroupsRelatedPrivileges(group_privileges);
+    m_privilegeGids.init(group_privileges);
 }
 
 ServiceImpl::~ServiceImpl()
@@ -793,15 +795,8 @@ int ServiceImpl::getPkgName(const std::string &appName, std::string &pkgName)
     return SECURITY_MANAGER_SUCCESS;
 }
 
-template <typename T>
-static void vectorRemoveDuplicates(std::vector<T> &vec)
-{
-    std::sort(vec.begin(), vec.end());
-    vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
-}
-
 int ServiceImpl::getAppGroups(const Credentials &creds, const std::string &appName,
-    std::vector<std::string> &groups)
+    std::vector<gid_t> &groups)
 {
     try {
         LogDebug("appName: " << appName);
@@ -818,19 +813,19 @@ int ServiceImpl::getAppGroups(const Credentials &creds, const std::string &appNa
 
         std::string pidStr = std::to_string(creds.pid);
         for (const auto &privilege : privileges) {
-            std::vector<std::string> privGroups;
-            m_priviligeDb.GetPrivilegeGroups(privilege, privGroups);
-            if (!privGroups.empty()) {
-                LogDebug("Considering privilege " << privilege << " with " <<
-                    privGroups.size() << " groups assigned");
-
-                if (m_cynara.check(appProcessLabel, privilege, uidStr, pidStr)) {
-                    groups.insert(groups.end(),
-                        std::make_move_iterator(privGroups.begin()),
-                        std::make_move_iterator(privGroups.end()));
-                    LogDebug("Cynara allowed, adding groups");
-                } else
-                    LogDebug("Cynara denied, not adding groups");
+            auto &pgids = m_privilegeGids.getGids(privilege);
+
+            LogDebug("Considering privilege " << privilege << " with " <<
+                     pgids.size() << " groups assigned");
+
+            if (pgids.empty())
+                continue;
+
+            if (m_cynara.check(appProcessLabel, privilege, uidStr, pidStr)) {
+                groups.insert(groups.end(), pgids.begin(), pgids.end());
+                LogDebug("Cynara allowed, adding groups");
+            } else {
+                LogDebug("Cynara denied, not adding groups");
             }
         }
         vectorRemoveDuplicates(groups);
@@ -1241,12 +1236,13 @@ int ServiceImpl::policyGetDesc(std::vector<std::string> &levels)
     return ret;
 }
 
-int ServiceImpl::policyGetGroups(std::vector<std::string> &groups)
+int ServiceImpl::policyGetGroups(std::vector<gid_t> &groups)
 {
     int ret = SECURITY_MANAGER_SUCCESS;
 
     try {
-        m_priviligeDb.GetGroups(groups);
+        auto &gids = m_privilegeGids.getGids();
+        groups.insert(groups.end(), gids.begin(), gids.end());
     } catch (const PrivilegeDb::Exception::Base &e) {
         LogError("Error while getting groups from database: " << e.DumpToString());
         return SECURITY_MANAGER_ERROR_SERVER_ERROR;
@@ -1255,7 +1251,7 @@ int ServiceImpl::policyGetGroups(std::vector<std::string> &groups)
     return ret;
 }
 
-int ServiceImpl::policyGroupsForUid(uid_t uid, std::vector<std::string> &groups)
+int ServiceImpl::policyGroupsForUid(uid_t uid, std::vector<gid_t> &groups)
 {
     int ret = SECURITY_MANAGER_SUCCESS;
 
@@ -1289,15 +1285,16 @@ int ServiceImpl::policyGroupsForUid(uid_t uid, std::vector<std::string> &groups)
                 return SECURITY_MANAGER_ERROR_UNKNOWN;
         }
 
-        std::vector<std::pair<std::string, std::string>> group2privVector;
-        m_priviligeDb.GetGroupsRelatedPrivileges(group2privVector);
-
-        for (const auto &g2p : group2privVector) {
-            m_cynaraAdmin.check(CYNARA_ADMIN_ANY, uidStr, g2p.second,
-                                             bucket, result, resultExtra, true);
-            if (result == CYNARA_ADMIN_ALLOW)
-                groups.push_back(g2p.first);
+        auto &privs = m_privilegeGids.getPrivileges();
+        for (auto &p : privs) {
+            m_cynaraAdmin.check(CYNARA_ADMIN_ANY, uidStr, p, bucket, result,
+                                resultExtra, true);
+            if (result == CYNARA_ADMIN_ALLOW) {
+                auto &gids = m_privilegeGids.getGids(p);
+                groups.insert(groups.end(), gids.begin(), gids.end());
+            }
         }
+        vectorRemoveDuplicates(groups);
     } catch (const CynaraException::Base &e) {
         LogError("Error while getting user type from Cynara: " << e.DumpToString());
         return SECURITY_MANAGER_ERROR_SERVER_ERROR;
index 6e1f03b3493b4861d6f87c00188c20902407355b..f3f5facdb491c4947ff08694e395a7afe48d557a 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "security-manager-types.h"
 
+#include <sys/types.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -91,37 +93,26 @@ int security_manager_prepare_app(const char *app_id);
 /**
  * This function returns array of groups bound to privileges of file resources.
  *
- * Caller needs to free memory allocated for the list using
- * security_manager_groups_free().
+ * Caller needs to free memory allocated for the list using free().
  *
  * @param[out] groups pointer to array of strings.
  * @param[out] groups_count number of strings in levels array.
  * @return API return code or error code.
  */
-int security_manager_groups_get(char ***groups, size_t *groups_count);
+int security_manager_groups_get(gid_t **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().
+ * Caller needs to free memory allocated for the list using 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.
- *
- * @param[in] groups array of strings returned by security_manager_groups_get() function.
- * @param[in] groups_count size of the groups array
- */
-void security_manager_groups_free(char **groups, size_t groups_count);
+int security_manager_groups_get_for_user(uid_t uid, gid_t **groups, size_t *groups_count);
 
 /**
  * Get package and application id of an application with given socket descriptor
index 318c38c8a74c99779f3df03f857fe31b99ddd034..1791de2a4dfaa2b06746157506fe0d74375bedcd 100644 (file)
@@ -9,6 +9,7 @@ INCLUDE_DIRECTORIES(
     ${NSS_PATH}/include
     ${DPL_PATH}/core/include
     ${DPL_PATH}/log/include
+    ${COMMON_PATH}/include
     )
 
 SET(NSS_SOURCES
index 3e9009c6c6e7ccbe6e873e3e4ce8c61f53d12519..0e2ae5e6d456681a38e569cf7e74796571048480 100644 (file)
 #include <cstddef>
 #include <sys/types.h>
 #include <pwd.h>
-#include <grp.h>
 #include <nss.h>
 #include <unistd.h>
 #include <cstdlib>
 
 #include <vector>
+#include <algorithm>
 
 #include <security-manager.h>
+#include <utils.h>
 
 namespace {
 
@@ -50,7 +51,28 @@ size_t getBufferSize()
 
 extern "C" {
 
-
+/**
+ * @param[in] user          User name
+ * @param[in] group_gid     Additional group already added to @a groupsp
+ * @param[in/out] start     Start index in @a groupsp. We should start writing at this index.
+ *                          In the end it should point to the first free slot in @a groupsp
+ * @param[in/out] size      Size of @a groupsp
+ * @param[in/out] groupsp   Output buffer for gids. Can be reallocated if needed. In such
+ *                          case @a size must be updated
+ * @param[int] limit        Maximum number of groups to be stored in @a groupsp.
+ *                          We can't write at or past this index
+ *                          0 means unlimited. Can be bigger than @a size.
+ * @param[out] errnop       Pointer to errno code
+ *
+ *
+ * *groupsp->|G|G|E|E|E|E|E|E|E|E| | | | | |
+ *                ^             ^         ^
+ *             *start        *size      limit
+ *
+ * |G| - groupsp array element already containing a gid
+ * |E| - empty groupsp array element
+ * | | - space not allocated by groupsp
+ */
 __attribute__((visibility("default")))
 enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t group_gid, long int *start,
                                                     long int *size, gid_t **groupsp,
@@ -84,7 +106,7 @@ enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t grou
             return NSS_STATUS_NOTFOUND;
         }
 
-        char **groups;
+        gid_t *groups;
         size_t groupsCount;
         ret = security_manager_groups_get_for_user(pwnam->pw_uid, &groups, &groupsCount);
 
@@ -92,6 +114,7 @@ enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t grou
             // If user is not managed by Security Manager, we want to apply all the groups
             ret = security_manager_groups_get(&groups, &groupsCount);
         }
+        auto groupsGuard = SecurityManager::makeUnique(groups, free);
 
         if (ret == SECURITY_MANAGER_ERROR_MEMORY) {
             *errnop = ENOMEM;
@@ -108,30 +131,8 @@ enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t grou
             return NSS_STATUS_UNAVAIL;
         }
 
-        std::vector<gid_t> result;
-
-        for (size_t i = 0; i < groupsCount; ++i) {
-            group *grnam = NULL;
-            group groupbuff;
-            do {
-                ret = TEMP_FAILURE_RETRY(getgrnam_r(groups[i], &groupbuff, buffer.data(), buffer.size(), &grnam));
-                if (ret == ERANGE && buffer.size() < MEMORY_LIMIT) {
-                    buffer.resize(buffer.size() << 1);
-                    continue;
-                }
-            } while(0);
-
-            if (ret == ERANGE) {
-                *errnop = ENOMEM;
-                return NSS_STATUS_UNAVAIL;
-            }
-
-            if (grnam)
-                result.push_back(grnam->gr_gid);
-        }
-
-        if (((*size) - (*start)) < static_cast<long int>(result.size())) {
-            long int required = (*start) + result.size();
+        if (((*size) - (*start)) < static_cast<long int>(groupsCount)) {
+            long int required = (*start) + groupsCount;
             // value bigger is the lowest power of 2 that is bigger than required value
             long int bigger = 1 << ((sizeof(unsigned long) << 3) - __builtin_clzl(static_cast<unsigned long>(required)));
 
@@ -144,12 +145,11 @@ enum nss_status _nss_securitymanager_initgroups_dyn(const char *user, gid_t grou
             *groupsp = ptr;
         }
 
-        for (auto e : result) {
-            (*groupsp)[(*start)++] = e;
-            if (limit > 0 && (*start) >= limit)
-                break;
-        }
-
+        long int cnt = groupsCount;
+        if (limit > 0 && limit - *start < cnt)
+            cnt = limit - *start;
+        std::copy(groups, groups + cnt, *groupsp + *start);
+        *start += cnt;
     } catch (...) {
         // We are leaving c++ code and going to pure c so this
         // Pokemon catch (catch them all) is realy required here.
index fe4f865b99c5b190c424fe918ecd5d8e0d9fa548..f91b05e5804f80ab7b8ef9c87bb37ec5ea417074 100644 (file)
@@ -228,7 +228,7 @@ void Service::processGetPkgName(MessageBuffer &buffer, MessageBuffer &send)
 void Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, const Credentials &creds)
 {
     std::string appName;
-    std::vector<std::string> groups;
+    std::vector<gid_t> groups;
     int ret;
 
     Deserialization::Deserialize(buffer, appName);
@@ -324,7 +324,7 @@ void Service::processPolicyGetDesc(MessageBuffer &send)
 
 void Service::processGroupsGet(MessageBuffer &send)
 {
-    std::vector<std::string> groups;
+    std::vector<gid_t> groups;
     int ret = serviceImpl.policyGetGroups(groups);
 
     Serialization::Serialize(send, ret);
@@ -336,7 +336,7 @@ void Service::processGroupsGet(MessageBuffer &send)
 void Service::processGroupsForUid(MessageBuffer &recv, MessageBuffer &send)
 {
     uid_t uid;
-    std::vector<std::string> groups;
+    std::vector<gid_t> groups;
 
     Deserialization::Deserialize(recv, uid);
 
index ed6280412a95f5c63537c48f86eb4632e295c451..53bac0aaa9e063dbff58728df53778431f154424 100644 (file)
@@ -35,34 +35,6 @@ BOOST_FIXTURE_TEST_SUITE(PRIVILEGE_DB_TEST_PRIVILEGE, PrivilegeDBFixture)
 
 // Privileges
 
-BOOST_AUTO_TEST_CASE(T800_get_groups_from_empty_db)
-{
-    std::vector<std::string> groups;
-    BOOST_REQUIRE_NO_THROW(getPrivDb()->GetGroups(groups));
-    BOOST_REQUIRE_MESSAGE(groups.size() == 0, "GetGroups found some groups in empty database");
-}
-
-BOOST_AUTO_TEST_CASE(T810_get_groups)
-{
-    int ret = system("sqlite3 " TEST_PRIVILEGE_DB_PATH " "
-    "\"BEGIN; "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege30', 'group3'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege10', 'group1'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege11', 'group1'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege20', 'group2'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege31', 'group3'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege32', 'group3'); "
-    "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('privilege41', 'group4'); "
-    "COMMIT;\" ");
-    BOOST_REQUIRE_MESSAGE(ret == 0, "Could not create populate the  database");
-    std::vector<std::string> groups;
-    BOOST_REQUIRE_NO_THROW(getPrivDb()->GetGroups(groups));
-    std::sort(groups.begin(), groups.end());
-    std::vector<std::string> expectedGroups = {"group1", "group2", "group3", "group4"};
-    BOOST_CHECK_EQUAL_COLLECTIONS(groups.begin(), groups.end(),
-        expectedGroups.begin(), expectedGroups.end());
-}
-
 BOOST_AUTO_TEST_CASE(T820_get_groups_related_privileges_from_empty_db)
 {
     std::vector<std::pair<std::string, std::string>> privileges;