- 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
#include <service_impl.h>
#include <check-proper-drop.h>
#include <utils.h>
+#include <group2gid.h>
#include <security-manager.h>
#include <client-offline.h>
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);
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)
return request.getStatus();
}
- std::vector<std::string> groupNames;
- request.recv(groupNames);
- return groupNamesToGids(groupNames, groups);
+ request.recv(groups);
+ return SECURITY_MANAGER_SUCCESS;
}
namespace Syscall {
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;
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)
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,
${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)
--- /dev/null
+/*
+ * 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 */
+
--- /dev/null
+/*
+ * 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 */
+
+
--- /dev/null
+/*
+ * 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 */
ESquashSharing,
EClearSharing,
EClearPrivatePaths,
- EGetPrivilegeGroups,
EGetUserApps,
EGetUserPkgs,
EGetAllPackages,
EGetAppsInPkg,
- EGetGroups,
EGetGroupsRelatedPrivileges,
EGetPkgAuthorId,
EAuthorIdExists,
{ 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=?"},
*/
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
*
*/
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)
*
#include "smack-rules.h"
#include "protocols.h"
#include "privilege_db.h"
+#include "privilege-gids.h"
namespace SecurityManager {
* @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.
*
* @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
*
* @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
Cynara m_cynara;
PrivilegeDb m_priviligeDb;
CynaraAdmin m_cynaraAdmin;
+ PrivilegeGids m_privilegeGids;
};
} /* namespace SecurityManager */
#include <functional>
#include <memory>
+#include <vector>
+#include <algorithm>
namespace SecurityManager {
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 */
--- /dev/null
+/*
+ * 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 */
});
}
-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>([&] {
});
}
-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>([&] {
/*
- * 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>
*
*/
#include <fcntl.h>
-#include <grp.h>
#include <linux/xattr.h>
#include <limits.h>
#include <pwd.h>
ServiceImpl::ServiceImpl()
{
+ PrivilegeGids::GroupPrivileges group_privileges;
+ m_priviligeDb.GetGroupsRelatedPrivileges(group_privileges);
+ m_privilegeGids.init(group_privileges);
}
ServiceImpl::~ServiceImpl()
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);
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);
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;
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;
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;
#include "security-manager-types.h"
+#include <sys/types.h>
+
#ifdef __cplusplus
extern "C" {
#endif
/**
* 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
${NSS_PATH}/include
${DPL_PATH}/core/include
${DPL_PATH}/log/include
+ ${COMMON_PATH}/include
)
SET(NSS_SOURCES
#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 {
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,
return NSS_STATUS_NOTFOUND;
}
- char **groups;
+ gid_t *groups;
size_t groupsCount;
ret = security_manager_groups_get_for_user(pwnam->pw_uid, &groups, &groupsCount);
// 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;
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)));
*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.
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);
void Service::processGroupsGet(MessageBuffer &send)
{
- std::vector<std::string> groups;
+ std::vector<gid_t> groups;
int ret = serviceImpl.policyGetGroups(groups);
Serialization::Serialize(send, ret);
void Service::processGroupsForUid(MessageBuffer &recv, MessageBuffer &send)
{
uid_t uid;
- std::vector<std::string> groups;
+ std::vector<gid_t> groups;
Deserialization::Deserialize(recv, uid);
// 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;