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 ##################################
-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
-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}
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})
#!/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
#include <cstdio>
#include <cstdlib>
#include <functional>
+#include <fstream>
#include <memory>
#include <unordered_set>
#include <utility>
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)
{
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);
//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);
});
}
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,
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
/*
* 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>
*
#include <cstdio>
#include <list>
+#include <utility>
#include <map>
#include <stdbool.h>
#include <string>
{ 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=?"},
* @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
GROUPS_GET,
APP_HAS_PRIVILEGE,
PATHS_REGISTER,
+ GROUPS_FOR_UID,
NOOP = 0x90,
};
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
/*
* 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>
*
#include <cstdio>
#include <list>
+#include <utility>
#include <string>
#include <iostream>
});
}
+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
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,
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.
*
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
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);
}
}
+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;