Add ConfigFile class for run-time reading and parsing of config files 87/239887/2
authorRafal Krypa <r.krypa@samsung.com>
Tue, 28 Nov 2017 07:49:46 +0000 (08:49 +0100)
committerDariusz Michaluk <d.michaluk@samsung.com>
Thu, 30 Jul 2020 11:35:37 +0000 (13:35 +0200)
New code reads config file and splits it into lines to vector, with one
element per file line. Each line is represented as vector itself, with
one element per white space separated token.
Lines that are empty or start with '#' are ignored.

New code is now used for parsing Smack policy templates and privilege to
group mapping.

Change-Id: I009cf2a33f0233a170666cfe27fd7604fb7f4340
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
12 files changed:
CMakeLists.txt
policy/security-manager-policy-reload.in
src/client/client-security-manager.cpp
src/common/CMakeLists.txt
src/common/config-file.cpp [new file with mode: 0644]
src/common/config.cpp
src/common/include/config-file.h [new file with mode: 0644]
src/common/include/config.h
src/common/include/smack-rules.h
src/common/smack-rules.cpp
test/CMakeLists.txt
test/test_smack-rules.cpp

index d3d885a9f385748449ca725a76c79ca3a95acd39..54b21aae8275d962b6c53e670656bd3b2f11388a 100644 (file)
@@ -47,15 +47,6 @@ 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(CMAKE_CXX_FLAGS_PROFILING  "-g -std=c++0x -O0 -pg -Wp,-U_FORTIFY_SOURCE")
index 4a9dd538c918fd94fb1daa25c9f2662b45d485d9..e789650f535bdd8445f29c1043f17cfbdf653f5a 100755 (executable)
@@ -2,7 +2,7 @@
 
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 POLICY_PATH=@POLICY_DIR@
-PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/@PRIVILEGE_GROUP_LIST_FILE@
+PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/privilege-group.list
 
 DB_FILE=`tzplatform-get TZ_SYS_DB | cut -d= -f2`/.security-manager.db
 
index 89c243a1c9a3ea8fedd5dafb9233043227274aa1..1e626d8bb1e1c7d7f9b16a5f8565d625c4fe3777 100644 (file)
@@ -28,7 +28,6 @@
 #include <cstdio>
 #include <cstdlib>
 #include <functional>
-#include <fstream>
 #include <memory>
 #include <unordered_set>
 #include <utility>
@@ -58,6 +57,8 @@
 #include <check-proper-drop.h>
 #include <utils.h>
 #include <group2gid.h>
+#include <config.h>
+#include <config-file.h>
 
 #include <security-manager.h>
 #include <client-offline.h>
@@ -1110,21 +1111,32 @@ void security_manager_policy_levels_free(char **levels, size_t levels_count)
     delete[] levels;
 }
 
-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);
+static void loadGroups(std::vector<gid_t> &vgroups)
+{
+    auto groupsMapData = ConfigFile(Config::PRIVILEGE_GROUP_LIST_FILE).read();
+    for (const auto &groupsMapEntry : groupsMapData) {
+        if (groupsMapEntry.size() != 2)
+            continue;
 
-    Group2Gid g2g;
+        const std::string &groupName = groupsMapEntry[1];
+        std::vector<char> buf(1024);
+        group *result = nullptr;
+        group grp;
 
-    while(input.getline(line, LINEMAX)) {
-        if (line[0] == '#')
-            continue;
-        char *pos = strchr(line, ' ');
-        if (pos == NULL)
-            continue;
-        pos++;
-        vgroups.push_back(g2g.get(std::string(pos)));
+        for (;;) {
+            int ret = TEMP_FAILURE_RETRY(getgrnam_r(groupName.c_str(), &grp, buf.data(), buf.size(), &result));
+            if (ret == ERANGE) {
+                buf.resize(buf.size() * 2);
+                continue;
+            }
+            if (result == nullptr && ret == 0)
+                ret = ENOENT;
+
+            if (ret != 0)
+                throw std::system_error(ret, std::system_category(), "getgrnam_r() failed");
+            break;
+        }
+        vgroups.push_back(result->gr_gid);
     }
 }
 
index d9be6b59711eae26e5dc1c25f2fc6f106cd08c6a..f4e465325c077020e7e7a24391786719ffd25f68 100644 (file)
@@ -47,6 +47,7 @@ SET(COMMON_SOURCES
     ${DPL_PATH}/db/src/naive_synchronization_object.cpp
     ${DPL_PATH}/db/src/sql_connection.cpp
     ${COMMON_PATH}/config.cpp
+    ${COMMON_PATH}/config-file.cpp
     ${COMMON_PATH}/connection.cpp
     ${COMMON_PATH}/credentials.cpp
     ${COMMON_PATH}/cynara.cpp
diff --git a/src/common/config-file.cpp b/src/common/config-file.cpp
new file mode 100644 (file)
index 0000000..9999e32
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ *  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        config-file.cpp
+ * @author      Rafal Krypa (r.krypa@samsung.com)
+ * @version     1.0
+ * @brief
+ */
+
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <config-file.h>
+#include <filesystem.h>
+
+namespace SecurityManager {
+
+std::vector<std::vector<std::string>> ConfigFile::read()
+{
+    std::vector<std::vector<std::string>> ret;
+    std::istringstream stream(FS::getTextFileContents(m_path));
+
+    std::string line;
+    while (getline(stream, line)) {
+        if (line.empty() || line[0] == '#')
+            continue;
+
+        std::istringstream stream(line);
+        ret.emplace_back(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>());
+    }
+
+    return ret;
+}
+
+} // namespace SecurityManager
index 2f38867c6b40297ebd4f4ed1b61e3e50c1066b64..30f6db3c66f0c297a25e3f2ddb6a2e90bd0fb26e 100644 (file)
@@ -41,6 +41,8 @@ const std::string PRIVILEGE_SHM              = "http://tizen.org/privilege/inter
 const std::string APPS_LABELS_FILE = "apps-labels";
 const std::string SKEL_DIR = "/etc/skel";
 
+const std::string PRIVILEGE_GROUP_LIST_FILE = POLICY_DIR "/privilege-group.list";
+
 const std::string PRIVACY_POLICY_DESC = "Ask user";
 #ifdef ASKUSER_ENABLED
 const bool IS_ASKUSER_ENABLED = true;
diff --git a/src/common/include/config-file.h b/src/common/include/config-file.h
new file mode 100644 (file)
index 0000000..309c93a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ *  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        config-file.h
+ * @author      Rafal Krypa (r.krypa@samsung.com)
+ * @version     1.0
+ * @brief
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+
+namespace SecurityManager {
+
+class ConfigFile {
+public:
+    ConfigFile(const std::string &path) : m_path(path) {}
+    std::vector<std::vector<std::string>> read();
+
+private:
+    const std::string m_path;
+};
+
+} // namespace SecurityManager
index f8ac57a3d393975b5daa934b1fa330297e4ed5f7..b2fae1e4a2a27223696aa4635d874a5a53ba0db3 100644 (file)
@@ -29,8 +29,8 @@
 namespace SecurityManager {
 
 namespace Config {
-/* Service name */
 
+/* Service name */
 extern const std::string SERVICE_NAME;
 
 /* Privileges required from users of our API */
@@ -45,6 +45,9 @@ extern const std::string PRIVILEGE_SHM;
 /* Files used in permitted label managment */
 extern const std::string APPS_LABELS_FILE;
 
+/* Policy files */
+extern const std::string PRIVILEGE_GROUP_LIST_FILE;
+
 extern const std::string SKEL_DIR;
 
 /* Ask-user policy description */
index 65c40dbaa27008d604cb1bb23adbfad489cb51db..736df18dbb3e41b178b4700aa6121495d2ab8f60 100644 (file)
@@ -36,7 +36,7 @@ namespace SecurityManager {
 class SmackRules
 {
 public:
-    typedef std::string Rule;
+    typedef std::vector<std::string> Rule;
     typedef std::vector<Rule> RuleVector;
     typedef std::vector<std::string> Pkgs;
     typedef std::vector<std::string> Labels;
index d673ffae25b6b224b564daf2896a035833236ac1..cea95662aebb3a5f72724dbe9cfe733a168d441b 100644 (file)
@@ -35,6 +35,7 @@
 #include <memory>
 #include <algorithm>
 
+#include "config-file.h"
 #include "dpl/log/log.h"
 #include "dpl/errno_string.h"
 #include "dpl/fstream_accessors.h"
@@ -175,25 +176,12 @@ void SmackRules::addFromTemplateFile(
         const std::string &pkgName,
         const int authorId)
 {
-    RuleVector templateRules;
-    std::string line;
-    std::ifstream templateRulesFile(templatePath);
-
-    if (!templateRulesFile.is_open()) {
-        LogError("Cannot open rules template file: " << templatePath);
-        ThrowMsg(SmackException::FileError, "Cannot open rules template file: " << templatePath);
-    }
-
-    while (std::getline(templateRulesFile, line))
-        if (!line.empty())
-            templateRules.push_back(line);
-
-    if (templateRulesFile.bad()) {
+    try {
+        addFromTemplate(ConfigFile(templatePath).read(), appProcessLabel, pkgName, authorId);
+    } catch (FS::Exception::Base) {
         LogError("Error reading template file: " << templatePath);
         ThrowMsg(SmackException::FileError, "Error reading template file: " << templatePath);
     }
-
-    addFromTemplate(templateRules, appProcessLabel, pkgName, authorId);
 }
 
 void SmackRules::addFromTemplate(
@@ -214,19 +202,16 @@ void SmackRules::addFromTemplate(
     if (authorId >= 0)
         pathTrustedLabel = SmackLabels::generatePathTrustedLabel(authorId);
 
-    for (auto rule : templateRules) {
-        if (rule.empty())
-            continue;
-
-        std::stringstream stream(rule);
-        std::string subject, object, permissions;
-        stream >> subject >> object >> permissions;
-
-        if (stream.fail() || !stream.eof()) {
-            LogError("Invalid rule template: " << rule);
-            ThrowMsg(SmackException::FileError, "Invalid rule template: " << rule);
+    for (auto &rule : templateRules) {
+        if (rule.size() != 3) {
+            LogError("Invalid rule template: " << rule.size() << " tokens");
+            ThrowMsg(SmackException::FileError, "Invalid rule template: " << rule.size() << " tokens");
         }
 
+        std::string subject = rule[0];
+        std::string object = rule[1];
+        std::string permissions = rule[2];
+
         strReplace(subject, SMACK_PROCESS_LABEL_TEMPLATE, appProcessLabel);
         strReplace(object,  SMACK_PROCESS_LABEL_TEMPLATE, appProcessLabel);
         strReplace(object,  SMACK_PATH_RW_LABEL_TEMPLATE, pathRWLabel);
index 57e2308feed50bb8cde9249581d9567084a0f96d..cb0721be61151c0f0b973bde701edb7bfebfc22c 100644 (file)
@@ -62,6 +62,7 @@ SET(SM_TESTS_SOURCES
     ${DPL_PATH}/log/src/abstract_log_provider.cpp
     ${DPL_PATH}/log/src/log.cpp
     ${DPL_PATH}/log/src/old_style_log_provider.cpp
+    ${PROJECT_SOURCE_DIR}/src/common/config-file.cpp
     ${PROJECT_SOURCE_DIR}/src/common/file-lock.cpp
     ${PROJECT_SOURCE_DIR}/src/common/privilege_db.cpp
     ${PROJECT_SOURCE_DIR}/src/common/smack-check.cpp
index e98159199259157914277faec3a88855d7444302..4503acff514dddce404d07422db89a48bb27c3f1 100644 (file)
@@ -163,20 +163,23 @@ BOOST_AUTO_TEST_CASE(T1120_smack_rules_exception)
 
 BOOST_FIXTURE_TEST_CASE(T1130_smack_rules_templates, RulesFixture)
 {
-    SmackRules::RuleVector templateRules = { "System ~PROCESS~ rwxat",
-                                             "~PROCESS~ System wx",
-                                             "~PROCESS~ ~PATH_RW~ rwxat",
-                                             "~PROCESS~ ~PATH_RO~ rxl",
-                                             "~PROCESS~ ~PATH_SHARED_RO~ rwxat",
-                                             "~PROCESS~ ~PATH_TRUSTED~ rwxat" };
+    SmackRules::RuleVector templateRules = {{"System", "~PROCESS~", "rwxat"},
+                                            {"~PROCESS~", "System", "wx"},
+                                            {"~PROCESS~", "~PATH_RW~", "rwxat"},
+                                            {"~PROCESS~", "~PATH_RO~", "rxl"},
+                                            {"~PROCESS~", "~PATH_SHARED_RO~", "rwxat"},
+                                            {"~PROCESS~", "~PATH_TRUSTED~", "rwxat"}};
 
     std::ofstream templateRulesFile;
     templateRulesFile.open(templateRulesFilePath);
-    for (auto templateRule : templateRules)
-        templateRulesFile << templateRule << std::endl;
+    for (auto &templateRule : templateRules) {
+        for (auto &templateRuleToken : templateRule)
+            templateRulesFile << templateRuleToken << ' ';
+        templateRulesFile << std::endl;
+    }
     templateRulesFile.close();
 
-    SmackRules::RuleVector expectedRules = { "System User::Pkg::pkgNameT1130 rwxat-",
+    std::vector<std::string> expectedRules = { "System User::Pkg::pkgNameT1130 rwxat-",
                                              "User::Pkg::pkgNameT1130 System -wx---",
                                              "User::Pkg::pkgNameT1130 User::Pkg::pkgNameT1130 rwxat-",
                                              "User::Pkg::pkgNameT1130 User::Pkg::pkgNameT1130::RO r-x--l",