Add test for libprivilege-control / perm_add_additional_rules.
authorLukasz Wojciechowski <l.wojciechow@partner.samsung.com>
Thu, 9 Jan 2014 13:34:48 +0000 (14:34 +0100)
committerMarcin Niesluchowski <m.niesluchow@samsung.com>
Mon, 27 Jan 2014 07:18:55 +0000 (08:18 +0100)
[Issue#]        SSDWSSP-679
[Feature]       Add new tests covering perm_add_additional_rules.
[Cause]         Function need to be tested.
[Solution]      Add tests checking database.
[Verification]  Build security-tests.
                Run tests on target:
                "security-tests.sh libprivilege-control --output=text \
                    --regexp=perm_add_additional_rules"

Change-Id: Idcb2f996d55aa1a7b557e830824e78af46a63f0e

12 files changed:
tests/libprivilege-control-tests/CMakeLists.txt
tests/libprivilege-control-tests/common/db.cpp
tests/libprivilege-control-tests/common/db.h
tests/libprivilege-control-tests/common/db_sqlite.cpp
tests/libprivilege-control-tests/common/db_sqlite.h
tests/libprivilege-control-tests/common/duplicates.cpp
tests/libprivilege-control-tests/common/duplicates.h
tests/libprivilege-control-tests/common/libprivilege-control_test_common.h
tests/libprivilege-control-tests/libprivilege-control_test_common.cpp
tests/libprivilege-control-tests/test_cases.cpp
tests/libprivilege-control-tests/test_cases_nosmack.cpp
tests/libprivilege-control-tests/test_cases_perm_add_additional_rules.cpp [new file with mode: 0644]

index bc6959d..5d8049b 100644 (file)
@@ -39,6 +39,7 @@ SET(LPC_TARGET_TEST_SOURCES
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/common/duplicates.cpp
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/libprivilege-control-test.cpp
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/test_cases.cpp
+    ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/test_cases_perm_add_additional_rules.cpp
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/test_cases_nosmack.cpp
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/test_cases_incorrect_params.cpp
     ${PROJECT_SOURCE_DIR}/tests/libprivilege-control-tests/test_cases_stress.cpp
@@ -65,6 +66,7 @@ ADD_EXECUTABLE(${LPC_TARGET_TEST} ${LPC_TARGET_TEST_SOURCES})
 TARGET_LINK_LIBRARIES(${LPC_TARGET_TEST}
     ${LPC_TARGET_DEP_LIBRARIES}
     tests-common
+    -lcrypt
     )
 
 #place for output file
index 5e7b01d..bdccd9e 100644 (file)
@@ -45,32 +45,28 @@ TestLibPrivilegeControlDatabase::TestLibPrivilegeControlDatabase() : m_base(DBAS
 {
 }
 
-void TestLibPrivilegeControlDatabase::test_db_after__perm_app_install(const Tracker& tracker,
-    const char* name)
+void TestLibPrivilegeControlDatabase::test_db_after__perm_app_install(const char* name)
 {
-    if(!m_base.is_open())
-        m_base.open(tracker);
+    if (!m_base.is_open())
+        m_base.open();
 
-    app_label(tracker, name);
-    app_permission(tracker, name, ALL_APPS, ALL_APPS,
-                   PERMISSION_PERSISTENT, PERMISSION_ENABLED);
+    app_label(name);
+    app_permission(name, ALL_APPS, ALL_APPS, PERMISSION_PERSISTENT, PERMISSION_ENABLED);
 }
 
-void TestLibPrivilegeControlDatabase::test_db_after__perm_app_uninstall(const Tracker& tracker,
-    const char* name)
+void TestLibPrivilegeControlDatabase::test_db_after__perm_app_uninstall(const char* name)
 {
-    if(!m_base.is_open())
-        m_base.open(tracker);
+    if (!m_base.is_open())
+        m_base.open();
 
-    app_not_label(tracker, name);
+    app_not_label(name);
 }
 
 void TestLibPrivilegeControlDatabase::test_db_after__perm_app_enable_permissions(
-    const Tracker& tracker, const char* name, app_type_t app_type, const char** perm_list,
-    bool persistent)
+    const char* name, app_type_t app_type, const char** perm_list, bool persistent)
 {
-    if(!m_base.is_open())
-        m_base.open(tracker);
+    if (!m_base.is_open())
+        m_base.open();
 
     string permission_type_name = app_type_name(app_type);
     string permission_group_type_name = app_type_group_name(app_type);
@@ -78,56 +74,67 @@ void TestLibPrivilegeControlDatabase::test_db_after__perm_app_enable_permissions
     string permission_name;
     int ret;
 
-    app_permission(tracker, name, permission_type_name, permission_type_name, is_volatile,
+    app_permission(name, permission_type_name, permission_type_name, is_volatile,
                    PERMISSION_ENABLED);
 
     int i;
-    for(i = 0; perm_list[i] != NULL; ++i) {
+    for (i = 0; perm_list[i] != NULL; ++i) {
         // Ignore empty lines
-        if(strspn(perm_list[i], " \t\n") == strlen(perm_list[i]))
+        if (strspn(perm_list[i], " \t\n") == strlen(perm_list[i]))
             continue;
 
         ret = base_name_from_perm(perm_list[i], permission_name);
-        RUNNER_ASSERT_MSG_BT(ret == PC_OPERATION_SUCCESS,
-                          "DB: Error testing \"" << __FUNCTION__ <<
-                          "\": permission : <" << perm_list[i] <<
-                          "> cannot be converted to basename (iri parse error)");
-        app_permission(tracker, name, permission_name, permission_group_type_name,
-                       is_volatile, PERMISSION_ENABLED);
+        RUNNER_ASSERT_MSG_BT(ret == PC_OPERATION_SUCCESS, "permission : <" << perm_list[i] <<
+                             "> cannot be converted to basename (iri parse error)");
+        app_permission(name, permission_name, permission_group_type_name, is_volatile,
+                       PERMISSION_ENABLED);
     }
 }
 
-void TestLibPrivilegeControlDatabase::app_label(const Tracker& tracker, const std::string& app_name)
+void TestLibPrivilegeControlDatabase::test_db_after__perm_add_additional_rules(
+    const additional_rules& rules)
+{
+    if (!m_base.is_open())
+        m_base.open();
+
+    additional_rules_table_create();
+
+    size_t i;
+    for (i = 0; i < rules.size(); ++i) {
+        additional_rules_check_single_rule(rules[i]);
+    }
+
+    additional_rules_table_check();
+}
+
+void TestLibPrivilegeControlDatabase::app_label(const std::string& app_name)
 {
     Sqlite3DBaseSelectResult result;
     ostringstream sql;
     sql << "SELECT app_id FROM app "
                "NATURAL JOIN label "
                "WHERE name == '" << app_name << "' ;";
-    m_base.execute(tracker, sql.str(), result);
+    m_base.execute(sql.str(), result);
 
-    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1 && result.rows[0].size() == 1,
-                      "DB: Error testing \"" << tracker.str() << "\": querry : <" << sql.str() <<
-                      "> returned [" << result.rows.size() << "] rows");
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1 && result.rows[0].size() == 1, "query : <" <<
+                         sql.str() << "> returned [" << result.rows.size() << "] rows");
 }
 
-void TestLibPrivilegeControlDatabase::app_not_label(const Tracker& tracker,
-    const std::string& app_name)
+void TestLibPrivilegeControlDatabase::app_not_label(const std::string& app_name)
 {
     Sqlite3DBaseSelectResult result;
     ostringstream sql;
     sql << "SELECT label_id FROM label "
                "WHERE name == '" << app_name << "' ;";
-    m_base.execute(tracker, sql.str(), result);
+    m_base.execute(sql.str(), result);
 
-    RUNNER_ASSERT_MSG_BT(result.rows.size() == 0,
-                      "DB: Error testing \"" << tracker.str() << "\": querry : <" << sql.str() <<
-                      "> returned [" << result.rows.size() << "] rows");
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 0, "query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
 }
 
-void TestLibPrivilegeControlDatabase::app_permission(const Tracker& tracker,
-    const std::string& app_name, const std::string& permission_name,
-    const std::string& permission_type_name, int is_volatile, int is_enabled)
+void TestLibPrivilegeControlDatabase::app_permission(const std::string& app_name,
+    const std::string& permission_name, const std::string& permission_type_name,
+    int is_volatile, int is_enabled)
 {
     Sqlite3DBaseSelectResult result;
     ostringstream sql;
@@ -143,9 +150,109 @@ void TestLibPrivilegeControlDatabase::app_permission(const Tracker& tracker,
                     "AND permission.name == '" << permission_name << "' "
                     "AND permission_type.type_name == '" << permission_type_name << "' "
                ";";
-    m_base.execute(tracker, sql.str(), result);
+    m_base.execute(sql.str(), result);
+
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1, "query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
+}
+
+void TestLibPrivilegeControlDatabase::additional_rules_table_create(void)
+{
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "CREATE TEMP TABLE IF NOT EXISTS test_additional_rules ("
+               "label_name TEXT, "
+               "app_path_type_name TEXT, "
+               "access INTEGER, "
+               "reverse INTEGER) ; ";
+    sql << "DELETE FROM test_additional_rules ; ";
+    m_base.execute(sql.str(), result);
+}
+
+void TestLibPrivilegeControlDatabase::additional_rules_check_single_rule(
+    const additional_rule& rule)
+{
+    static const std::set<std::string> allowed_objects = {"~PUBLIC_PATH~",
+                                                          "~GROUP_PATH~",
+                                                          "~SETTINGS_PATH~",
+                                                          "~NPRUNTIME_PATH~"};
+    if (allowed_objects.find(rule.object) == allowed_objects.end())
+        return;
+
+    //remove prefix and postfix ~
+    std::string path = rule.object.substr(1, rule.object.size() - 2);
+
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "INSERT OR IGNORE INTO test_additional_rules VALUES ('"
+        << rule.subject << "', '"
+        << path << "', "
+        << str_to_access(rule.access) << ", "
+        << (rule.reverse ? "1" : "0") << ") ;";
+    m_base.execute(sql.str(), result);
+
+    label(rule.subject);
+    app_path_type(path);
+    label_app_path_type_rule(rule, path);
+}
+
+void TestLibPrivilegeControlDatabase::label(const std::string& label)
+{
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "SELECT label_id FROM label "
+               "WHERE name == '" << label << "' ;";
+    m_base.execute(sql.str(), result);
+
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1,"query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
+}
+
+void TestLibPrivilegeControlDatabase::app_path_type(const std::string& path)
+{
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "SELECT * FROM app_path_type "
+               "WHERE name == '" << path << "' ;";
+    m_base.execute(sql.str(), result);
+
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1, "query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
+}
+
+void TestLibPrivilegeControlDatabase::label_app_path_type_rule(const additional_rule& rule,
+    const std::string& path)
+{
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "SELECT * FROM label_app_path_type_rule "
+               "INNER JOIN label USING (label_id) "
+               "INNER JOIN app_path_type USING (app_path_type_id) "
+               "WHERE "
+                   "label.name == '" << rule.subject << "' "
+                   "AND app_path_type.name == '" << path << "' "
+                   "AND is_reverse == " << (rule.reverse ? "1" : "0") << " "
+                   "AND access == " << str_to_access(rule.access) << " ;";
+    m_base.execute(sql.str(), result);
+
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1, "query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
+}
+
+void TestLibPrivilegeControlDatabase::additional_rules_table_check(void)
+{
+    Sqlite3DBaseSelectResult result;
+    ostringstream sql;
+    sql << "SELECT label.name AS label_name, "
+               "app_path_type.name AS app_path_type_name, "
+               "access AS access, "
+               "is_reverse AS reverse "
+               "FROM label_app_path_type_rule "
+               "INNER JOIN label USING (label_id) "
+               "INNER JOIN app_path_type USING (app_path_type_id) "
+               "EXCEPT SELECT * FROM test_additional_rules ;";
+    m_base.execute(sql.str(), result);
 
-    RUNNER_ASSERT_MSG_BT(result.rows.size() == 1,
-                      "DB: Error testing \"" << tracker.str() << "\": querry : <" << sql.str() <<
-                      "> returned [" << result.rows.size() << "] rows");
+    RUNNER_ASSERT_MSG_BT(result.rows.size() == 0, "query : <" << sql.str() << "> returned [" <<
+                         result.rows.size() << "] rows");
 }
index c3e8162..95b2f1f 100644 (file)
@@ -25,7 +25,7 @@
 #define LIBPRIVILEGE_CONTROL_TEST_DB_H_
 
 #include <privilege-control.h>
-#include <tracker.h>
+#include "libprivilege-control_test_common.h"
 #include "db_sqlite.h"
 
 /**
@@ -50,34 +50,41 @@ public:
  *
  * It checks existence of proper: label, app records and permission for ALL_APPS for installed app.
  *
- * @param tracker       make assertion comments if error more useful
- * @param name  name of installed app
+ * @param name                  name of installed app
  */
-    void test_db_after__perm_app_install(const Tracker& tracker, const char* name);
+    void test_db_after__perm_app_install(const char* name);
 
 /**
- * @brief Method for testing database after "perm_app_install" was run.
+ * @brief Method for testing database after "perm_app_uninstall" was run.
  *
- * It checks existence of proper: label, app records and permission for ALL_APPS for installed app.
+ * It checks absence of proper: label for installed app.
  *
- * @param tracker       make assertion comments if error more useful
- * @param name  name of installed app
+ * @param name                  name of uninstalled app
  */
-    void test_db_after__perm_app_uninstall(const Tracker& tracker, const char* name);
+    void test_db_after__perm_app_uninstall(const char* name);
 
 /**
  * @brief Method for testing database after "perm_app_enable_permissions" was run.
  *
  * It checks existence of proper permissions from perm_list and main permission for whole app_type.
  *
- * @param tracker       make assertion comments if error more useful
- * @param name          name of application
- * @param app_type      type of application (EFL, WRT, etc. )
- * @param perm_list     list of permission to enable
- * @param persistent    persistence or volatileness of permissions
+ * @param name                  name of application
+ * @param app_type              type of application (EFL, WRT, etc. )
+ * @param perm_list             list of permission to enable
+ * @param persistent            persistence or volatileness of permissions
  */
-    void test_db_after__perm_app_enable_permissions(const Tracker& tracker, const char* name,
-        app_type_t app_type, const char** perm_list, bool persistent);
+    void test_db_after__perm_app_enable_permissions(const char* name, app_type_t app_type,
+        const char** perm_list, bool persistent);
+
+/**
+ * @brief Method for testing database after "perm_add_additional_rules" was run.
+ *
+ * It checks database's table "label_app_path_type_rule" for 100% compatibility with rules.
+ * Argument rules for this function should be prepared with "additional_rules_parse()"
+ *
+ * @param rules                 set of rules to be checked
+ */
+    void test_db_after__perm_add_additional_rules(const additional_rules& rules);
 
 private:
 /**
@@ -92,31 +99,74 @@ private:
 /**
  * @brief Check existence of label related records for given app.
  *
- * @param tracker       make assertion comments if error more useful
- * @param app_name      name of application
+ * @param app_name              name of application
  */
-    void app_label(const Tracker& tracker, const std::string& app_name);
+    void app_label(const std::string& app_name);
 
 /**
  * @brief Check absence of label record for given app.
  *
- * @param tracker       make assertion comments if error more useful
- * @param app_name      name of application
+ * @param app_name              name of application
  */
-    void app_not_label(const Tracker& tracker, const std::string& app_name);
+    void app_not_label(const std::string& app_name);
 
 /**
  * @brief It checks existence of single permission.
- * @param tracker               make assertion comments if error more useful
+ *
  * @param app_name              name of application
  * @param permission_name       name of permission
  * @param permission_type_name  name of permission type
  * @param is_volatile           persistence or volatileness of permissions
  * @param is_enabled            permission enable flag
  */
-    void app_permission(const Tracker& tracker, const std::string& app_name,
-        const std::string& permission_name, const std::string& permission_type_name,
-        int is_volatile, int is_enabled);
+    void app_permission(const std::string& app_name, const std::string& permission_name,
+        const std::string& permission_type_name, int is_volatile, int is_enabled);
+
+/**
+ * @brief It prepares temporary database infrastructure needed to test perm_add_additional_rules
+ *
+ * Temporary database table is used for gathering checked records. After all records are checked
+ * table allows to find unchecked ones.
+ */
+    void additional_rules_table_create(void);
+
+/**
+ * @brief It checks single additional record (and marks it in temporary table)
+ *
+ * @param rule                  additional rule to be checked
+ */
+    void additional_rules_check_single_rule(const additional_rule& rule);
+
+/**
+ * @brief Checks existence of single record in label table
+ *
+ * @param label                 label to be checked
+ */
+    void label(const std::string& label);
+
+/**
+ * @brief Checks existence of single record in app_path_type table
+ *
+ * @param path                  path to be checked
+ */
+    void app_path_type(const std::string& path);
+
+/**
+ * @brief Checks existence of single record in label_app_path_type_rule table
+ *
+ * @param rule                  rule to be checked (object field is ignored
+ *                              only: subject, isreverse and access fields are used)
+ * @param path                  path to be checked (as object of rule)
+ */
+    void label_app_path_type_rule(const additional_rule& rule, const std::string& path);
+
+/**
+ * @brief It checks temporary database for additional unchecked records
+ *
+ * It counts the difference between true database table and temporary one.
+ * It is an error if any record is found.
+ */
+    void additional_rules_table_check(void);
 };
 
 #endif /* LIBPRIVILEGE_CONTROL_TEST_DB_H_ */
index 23ae2a4..e24003a 100644 (file)
@@ -36,28 +36,22 @@ Sqlite3DBase::~Sqlite3DBase()
 
 #define VFS_NOT_USED    NULL
 
-void Sqlite3DBase::open(const Tracker& tracker)
+void Sqlite3DBase::open(void)
 {
-    if(m_db_handle) //database already opened
+    if (m_db_handle) //database already opened
         return;
 
     int ret = sqlite3_open_v2(m_db_path.c_str(), &m_db_handle, m_flags, VFS_NOT_USED);
-    RUNNER_ASSERT_MSG_BT(m_db_handle,
-                      "DB: Error testing \"" << tracker.str() <<
-                      "\" Sqlite3DBase: Error opening the database: Unable to allocate memory.");
-    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK,
-                      "DB: Error testing \"" << tracker.str() <<
-                      "\" Sqlite3DBase: Error opening the database: " <<
-                      sqlite3_errmsg(m_db_handle));
+    RUNNER_ASSERT_MSG_BT(m_db_handle, "Error opening the database: Unable to allocate memory.");
+    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK, "Error opening the database: " <<
+                         sqlite3_errmsg(m_db_handle));
 }
 
-void Sqlite3DBase::close(const Tracker& tracker)
+void Sqlite3DBase::close(void)
 {
     int ret = sqlite3_close(m_db_handle);
-    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK,
-                      "DB: Error testing \"" << tracker.str() <<
-                      "\" Sqlite3DBase: Error closing the database: " <<
-                      sqlite3_errmsg(m_db_handle));
+    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK, "Error closing the database: " <<
+                         sqlite3_errmsg(m_db_handle));
 
     m_db_handle = NULL;
 }
@@ -67,22 +61,19 @@ bool Sqlite3DBase::is_open(void) const
     return !!m_db_handle;
 }
 
-void Sqlite3DBase::execute(const Tracker& tracker, const std::string& sql_querry,
-    Sqlite3DBaseSelectResult& result)
+void Sqlite3DBase::execute(const std::string& sql_query, Sqlite3DBaseSelectResult& result)
 {
     char* tmp = NULL;
     std::string errmsg;
 
-    int ret = sqlite3_exec(m_db_handle, sql_querry.c_str(), callback, &result, &tmp);
-    if(tmp) {
+    int ret = sqlite3_exec(m_db_handle, sql_query.c_str(), callback, &result, &tmp);
+    if (tmp) {
         errmsg.assign(tmp);
     }
     sqlite3_free(tmp);
 
-    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK || ret == SQLITE_ABORT,
-                      "DB: Error testing \"" << tracker.str() <<
-                      "\" Sqlite3DBase: Error executing statement <" << sql_querry << "> : " <<
-                      errmsg);
+    RUNNER_ASSERT_MSG_BT(ret == SQLITE_OK || ret == SQLITE_ABORT, "Error executing statement <" <<
+                         sql_query << "> : " << errmsg);
 }
 
 int Sqlite3DBase::callback(void* p_result, int cols, char** data, char** header)
@@ -91,13 +82,13 @@ int Sqlite3DBase::callback(void* p_result, int cols, char** data, char** header)
     Sqlite3DBaseSelectResult* result = static_cast<Sqlite3DBaseSelectResult*>(p_result);
 
     // if this is first record get column names
-    if(result->rows.empty()) {
-        for(i = 0; i < cols; ++i) {
+    if (result->rows.empty()) {
+        for (i = 0; i < cols; ++i) {
             result->header.push_back(header[i] ? header[i] : "");
         }
     }
     result->rows.push_back(Sqlite3Row());
-    for(i = 0; i < cols; ++i) {
+    for (i = 0; i < cols; ++i) {
         result->rows.back().push_back(data[i] ? data[i] : "");
     }
     return SQLITE_OK;
index 0058c33..32d2225 100644 (file)
@@ -27,7 +27,6 @@
 #include <vector>
 #include <string>
 #include <sqlite3.h>
-#include <tracker.h>
 
 /**
  * @def         DB_SQLITE_READWRITE_FLAG
 
 /**
  * @typedef     Sqlite3HeaderName
- * @brief       Holds single column name of sqlite select querry response.
+ * @brief       Holds single column name of sqlite select query response.
  */
 typedef std::string Sqlite3HeaderName;
 
 /**
  * @typedef     Sqlite3HeaderNameVector
- * @brief       Holds column names vector of sqlite select querry response.
+ * @brief       Holds column names vector of sqlite select query response.
  */
 typedef std::vector<Sqlite3HeaderName> Sqlite3HeaderNameVector;
 
 /**
  * @typedef     Sqlite3RowCell
- * @brief       Holds single cell of row of sqlite select querry response.
+ * @brief       Holds single cell of row of sqlite select query response.
  */
 typedef std::string Sqlite3RowCell;
 
 /**
  * @typedef     Sqlite3Row
- * @brief       Holds single row of sqlite select querry response.
+ * @brief       Holds single row of sqlite select query response.
  */
 typedef std::vector<Sqlite3RowCell> Sqlite3Row;
 
 /**
  * @typedef     Sqlite3RowVector
- * @brief       Holds multiple rows of sqlite select querry response.
+ * @brief       Holds multiple rows of sqlite select query response.
  */
 typedef std::vector<Sqlite3Row> Sqlite3RowVector;
 
 /**
  * @class       Sqlite3DBaseSelectResult
- * @brief       Sqlite3 select querry response.
+ * @brief       Sqlite3 select query response.
  *
  * Fields are public as there is no complicated logic to operate on them
  */
@@ -83,13 +82,13 @@ struct Sqlite3DBaseSelectResult
 {
 /**
  * @var         header
- * @brief       Sqlite select querry column names
+ * @brief       Sqlite select query column names
  */
     Sqlite3HeaderNameVector header;
 
 /**
  * @var         rows
- * @brief       Sqlite select querry rows vector
+ * @brief       Sqlite select query rows vector
  */
     Sqlite3RowVector rows;
 };
@@ -123,20 +122,16 @@ public:
  *
  * If database is already opened do nothing.
  *
- * @param tracker       make assertion comments if error more useful
- *
  * @throw DPL::Test::TestRunner::TestFailed    when opening database fails
  */
-    void open(const Tracker& tracker);
+    void open(void);
 
 /**
  * @brief Close database.
  *
- * @param tracker       make assertion comments if error more useful
- *
  * @throw DPL::Test::TestRunner::TestFailed    when closing database fails
  */
-    void close(const Tracker& tracker);
+    void close(void);
 
 /**
  * @brief Get database connection status.
@@ -147,16 +142,14 @@ public:
     bool is_open(void) const;
 
 /**
- * @brief Execute SQL querry on database
+ * @brief Execute SQL query on database
  *
- * @param tracker       make assertion comments if error more useful
- * @param sql_querry    SQL querry
+ * @param sql_query     SQL query
  * @param result        returned result
  *
- * @throw DPL::Test::TestRunner::TestFailed    when execution of querry fails
+ * @throw DPL::Test::TestRunner::TestFailed    when execution of query fails
  */
-    void execute(const Tracker& tracker, const std::string& sql_querry,
-        Sqlite3DBaseSelectResult& result);
+    void execute(const std::string& sql_query, Sqlite3DBaseSelectResult& result);
 
 private:
 /**
index 4a38307..4057562 100644 (file)
 #include <iri.h>
 #include <algorithm>
 #include <string>
+#include <set>
+#include <sys/smack.h>
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE
+#endif
+#include <unistd.h>
 #include "duplicates.h"
 
 std::string app_type_name(app_type_t app_type)
@@ -77,7 +83,7 @@ std::string app_type_group_name(app_type_t app_type)
 int base_name_from_perm(const char *perm, std::string& name)
 {
     iri_t *iris = iri_parse(perm);
-    if(iris == NULL || iris->host == NULL)
+    if (iris == NULL || iris->host == NULL)
     {
         iri_destroy(iris);
         return PC_ERR_INVALID_PARAM;
@@ -88,7 +94,7 @@ int base_name_from_perm(const char *perm, std::string& name)
     std::string path;
     std::string::size_type pos;
 
-    if(iris->path == NULL)
+    if (iris->path == NULL)
     {
         path = iris->host;
     }
@@ -97,7 +103,7 @@ int base_name_from_perm(const char *perm, std::string& name)
         path = iris->path;
         host = iris->host;
         pos = host.rfind('.');
-        if(pos != std::string::npos)
+        if (pos != std::string::npos)
         {
             host_dot = host.substr(pos + 1) + ".";
             host = host.substr(0, pos);
@@ -112,3 +118,85 @@ int base_name_from_perm(const char *perm, std::string& name)
 
     return PC_OPERATION_SUCCESS;
 }
+
+bool is_wildcard(const std::string& label)
+{
+    static const std::set<std::string> wildcards = { "~ALL_APPS~",
+                                                     "~ALL_APPS_WITH_SAME_PERMISSION~",
+                                                     "~PUBLIC_PATH~",
+                                                     "~GROUP_PATH~",
+                                                     "~SETTINGS_PATH~",
+                                                     "~NPRUNTIME_PATH~" };
+    return (wildcards.find(label) != wildcards.end());
+}
+
+bool smack_label_is_valid(const std::string& label)
+{
+    if (label.empty() ||
+        label.size() > SMACK_LABEL_LEN ||
+        label[0] == '-' ||
+        label.find_first_of("~ /\"\\'") != std::string::npos)
+        return false;
+    return true;
+}
+
+/**
+ * @brief access flags codes used by libprivilege database
+ */
+const int RDB_ACCESS_READ = 1;
+const int RDB_ACCESS_WRITE = 2;
+const int RDB_ACCESS_EXEC = 4;
+const int RDB_ACCESS_APPEND = 8;
+const int RDB_ACCESS_TRANSMUTE = 16;
+const int RDB_ACCESS_LOCK = 32;
+
+int str_to_access(const std::string& str)
+{
+    int access = 0;
+
+    for (auto i = 0U; i < str.size(); ++i) {
+        switch (str[i]) {
+        case 'R':
+        case 'r': access |= RDB_ACCESS_READ; break;
+
+        case 'W':
+        case 'w': access |= RDB_ACCESS_WRITE; break;
+
+        case 'X':
+        case 'x': access |= RDB_ACCESS_EXEC; break;
+
+        case 'A':
+        case 'a': access |= RDB_ACCESS_APPEND; break;
+
+        case 'T':
+        case 't': access |= RDB_ACCESS_TRANSMUTE; break;
+
+        case 'L':
+        case 'l': access |= RDB_ACCESS_LOCK; break;
+
+        case '-': break;
+
+        default: // An unknown permission
+            return -1;
+            }
+    }
+    return access;
+}
+
+std::string smack_label_for_path(const std::string& app_id, const std::string& path)
+{
+    std::string ret;
+
+    /* Prefix $1$ causes crypt() to use MD5 function */
+    const std::string salt = "$1$" + app_id;
+
+    char* label = crypt(path.c_str(), salt.c_str());
+    if (label) {
+        ret = label;
+        /* crypt() output may contain slash character,
+         * which is not legal in Smack labels */
+        std::replace(ret.begin(), ret.end(), '/', '%');
+    }
+
+    return ret;
+}
index 3b74656..292e108 100644 (file)
@@ -65,4 +65,47 @@ std::string app_type_group_name(app_type_t app_type);
  */
 int base_name_from_perm(const char *perm, std::string& name);
 
+/**
+ * @brief check if string is libprivilege wildcard
+ *
+ * @ingroup RDB internal functions test duplicate
+ *
+ * @param  label    string to be checked
+ * @return          true if label is a wildcard
+ *                  false otherwise
+ */
+bool is_wildcard(const std::string& label);
+
+/**
+ * @brief check if smack label is valid
+ *
+ * @ingroup RDB internal functions test duplicate
+ *
+ * @param  label    label to be checked
+ * @return          true if label is valid
+ *                  false otherwise
+ */
+bool smack_label_is_valid(const std::string& label);
+
+/**
+ * @brief encodes string defining access to int format used in libprivilege database
+ *
+ * @ingroup RDB internal functions test duplicate
+ *
+ * @param  str      access in string format
+ * @return          access in int format (ored RDB_ACCESS_* flags)
+ */
+int str_to_access(const std::string& str);
+
+/**
+ * @brief creates smack label for given path for application with given app_id as MD5
+ *
+ * @ingroup RDB internal functions test duplicate
+ *
+ * @param  app_id   application id
+ * @param  path     path for which label should be created
+ * @return          smack label for path
+ */
+std::string smack_label_for_path(const std::string& app_id, const std::string& path);
+
 #endif /* LIBPRIVILEGE_CONTROL_TEST_DUPLICATES_H_ */
index e8d8e15..c56b74b 100644 (file)
@@ -449,4 +449,27 @@ void test_app_disable_permissions_efl(bool smack);
 void test_app_disable_permissions(bool smack);
 void test_appsettings_privilege(bool smack);
 
+// Parsed form of single libprivilege additional rule.
+struct additional_rule
+{
+    std::string subject;
+    std::string object;
+    std::string access;
+    bool reverse;
+};
+
+typedef std::vector<additional_rule> additional_rules;
+
+bool additional_rules_parse(const char** smack_rules, additional_rules& rules);
+
+void restore_original_additional_rules(void);
+
+class RestoreAdditionalRulesGuard
+{
+public:
+    ~RestoreAdditionalRulesGuard() {
+        restore_original_additional_rules();
+    }
+};
+
 #endif /* LIBPRIVILEGE_CONTROL_TEST_COMMON_H_ */
index e15c978..c422220 100644 (file)
  */
 
 #include <fcntl.h>
-#include <iostream>
+#include <fstream>
 #include <set>
 #include <string>
+#include <string.h>
 #include <sys/sendfile.h>
+#include <sys/smack.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <vector>
+
 #include <libprivilege-control_test_common.h>
 #include <tests_common.h>
-#include <sys/smack.h>
+#include "common/duplicates.h"
 
 #define CANARY_LABEL             "tiny_yellow_canary"
 
@@ -758,3 +764,57 @@ void test_appsettings_privilege(bool smack)
 
     DB_END
 }
+
+// This function takes libprivilege additional smack_rules in same format as libprivilege,
+// parses them in same way as libprivilege.
+// If functions succeeds in parsing it returns true and fills rules parameter with parsed rules.
+// If smack_rules cannot be parsed false is returned.
+bool additional_rules_parse(const char** smack_rules, additional_rules& rules)
+{
+    const size_t ACC_LEN = 6;
+    rules.clear();
+    for (int i = 0; smack_rules[i] != NULL ; ++i)
+    {
+        std::string line(smack_rules[i]);
+        additional_rule rule;
+
+        // Ignore empty lines
+        if (line.find_first_not_of(" \t\n") == std::string::npos)
+            continue;
+
+        // Split
+        std::stringstream(line) >> rule.subject >> rule.object >> rule.access;
+        // If last element is empty - split failed
+        if (rule.access.empty() || rule.object.length() > SMACK_LABEL_LEN ||
+            rule.subject.length() > SMACK_LABEL_LEN || rule.access.length() > ACC_LEN)
+            return false;
+        rule.reverse = false;
+
+        // Rearrange
+        if (is_wildcard(rule.subject))
+        {
+            rule.subject.swap(rule.object);
+            rule.reverse = true;
+        }
+
+        // Check validity of subject
+        if (!smack_label_is_valid(rule.subject))
+            return false;
+
+        rules.push_back(rule);
+    }
+    return true;
+}
+
+void restore_original_additional_rules(void)
+{
+    std::ifstream file("/usr/share/privilege-control/ADDITIONAL_RULES.smack");
+    std::string line;
+    std::vector<const char*> rules;
+
+    while(std::getline(file, line))
+        rules.push_back(strdupa(line.c_str()));
+    rules.push_back(NULL);
+
+    perm_add_additional_rules(rules.data());
+}
index 8526c5b..874dbd8 100644 (file)
 #include <dpl/log/log.h>
 #include <tests_common.h>
 #include <libprivilege-control_test_common.h>
-#include <tracker.h>
+#include "common/duplicates.h"
 #include "common/db.h"
 
-#include <iostream>
-
 #define SMACK_STARTUP_RULES_FILE "/opt/etc/smack-app-early/accesses.d/rules"
 
 #define EARLY_RULE_SUBJECT    "livebox.web-provider"
@@ -693,7 +691,7 @@ RUNNER_TEST(privilege_control07_app_uninstall)
     DB_END
 
     TestLibPrivilegeControlDatabase db_test;
-    db_test.test_db_after__perm_app_uninstall(TRACE_FROM_HERE, APP_ID);
+    db_test.test_db_after__perm_app_uninstall(APP_ID);
 }
 
 /*
@@ -1452,6 +1450,8 @@ RUNNER_TEST_SMACK(privilege_control20_app_setup_path_npruntime)
     std::string nptargetlabel = std::string(APP_NPRUNTIME) + ".npruntime";
     char *label = NULL;
 
+    restore_original_additional_rules();
+
     DB_BEGIN
 
     result = perm_app_uninstall(APP_NPRUNTIME);
@@ -1521,8 +1521,8 @@ RUNNER_TEST(privilege_control21_early_rules)
     DB_END
 
     TestLibPrivilegeControlDatabase db_test;
-    db_test.test_db_after__perm_app_install(TRACE_FROM_HERE, APP_ID);
-    db_test.test_db_after__perm_app_install(TRACE_FROM_HERE, APP_TEST_APP_1);
+    db_test.test_db_after__perm_app_install(APP_ID);
+    db_test.test_db_after__perm_app_install(APP_TEST_APP_1);
 
     DB_BEGIN
 
index 3cf4eab..f73974e 100644 (file)
@@ -41,7 +41,6 @@
 #include <privilege-control.h>
 #include <tests_common.h>
 #include <libprivilege-control_test_common.h>
-#include <tracker.h>
 #include "common/db.h"
 
 #define APP_USER_NAME "app"
@@ -177,9 +176,8 @@ RUNNER_TEST_NOSMACK(privilege_control04_add_permissions_nosmack)
     check_app_has_permission(APP_ID, APP_TYPE_EFL, PRIVS_EFL, true);
 
     TestLibPrivilegeControlDatabase db_test;
-    db_test.test_db_after__perm_app_install(TRACE_FROM_HERE, APP_ID);
-    db_test.test_db_after__perm_app_enable_permissions(TRACE_FROM_HERE, APP_ID, APP_TYPE_EFL,
-                                                       PRIVS_EFL, TRUE);
+    db_test.test_db_after__perm_app_install(APP_ID);
+    db_test.test_db_after__perm_app_enable_permissions(APP_ID, APP_TYPE_EFL, PRIVS_EFL, TRUE);
 }
 
 void set_app_privilege_nosmack(int line_no,
@@ -493,9 +491,8 @@ RUNNER_TEST_NOSMACK(privilege_control11_app_enable_permissions_nosmack)
     RUNNER_ASSERT_MSG_BT(result == -1, "Permissions shouldn't be added. Result: " << result);
 
     TestLibPrivilegeControlDatabase db_test;
-    db_test.test_db_after__perm_app_install(TRACE_FROM_HERE, WGT_APP_ID);
-    db_test.test_db_after__perm_app_enable_permissions(TRACE_FROM_HERE, WGT_APP_ID, APP_TYPE_WGT,
-                                                       PRIVS2, TRUE);
+    db_test.test_db_after__perm_app_install(WGT_APP_ID);
+    db_test.test_db_after__perm_app_enable_permissions(WGT_APP_ID, APP_TYPE_WGT, PRIVS2, TRUE);
 
     DB_BEGIN
 
@@ -506,7 +503,7 @@ RUNNER_TEST_NOSMACK(privilege_control11_app_enable_permissions_nosmack)
 
     DB_END
 
-    db_test.test_db_after__perm_app_install(TRACE_FROM_HERE, WGT_APP_ID);
+    db_test.test_db_after__perm_app_install(WGT_APP_ID);
 }
 
 RUNNER_CHILD_TEST_NOSMACK(privilege_control11_app_enable_permissions_efl_nosmack)
diff --git a/tests/libprivilege-control-tests/test_cases_perm_add_additional_rules.cpp b/tests/libprivilege-control-tests/test_cases_perm_add_additional_rules.cpp
new file mode 100644 (file)
index 0000000..525a33e
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2014 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        test_cases_perm_add_additional_rules.cpp
+ * @author      Lukasz Wojciechowski (l.wojciechow@partner.samsung.com)
+ * @version     1.0
+ * @brief       libprivilege-control test_cases_perm_add_additional_rules tests
+ */
+
+#include <string>
+#include <vector>
+#include <functional>
+#include <memory>
+#include <sys/smack.h>
+
+#include <privilege-control.h>
+#include <dpl/test/test_runner.h>
+#include <tests_common.h>
+#include <libprivilege-control_test_common.h>
+#include "common/duplicates.h"
+#include "common/db.h"
+
+const char* additional_rules_empty[] = {
+    NULL };
+
+const char* additional_rules_rollback[] = {
+    "app1 ~PUBLIC_PATH~ rw",
+    "~PUBLIC_PATH~ app2 rw",
+    "app3 ~GROUP_PATH~ rw",
+    "~GROUP_PATH~ app4 rw",
+    "app5 ~SETTINGS_PATH~ rw",
+    "~SETTINGS_PATH~ app6 rw",
+    "app7 ~NPRUNTIME_PATH~ rw",
+    "~NPRUNTIME_PATH~ app8 rw",
+    NULL };
+
+
+const char* additional_rules_test_case_bad_01[] = {
+    "AAA  BBB",
+    NULL };
+
+const char* additional_rules_test_case_bad_02[] = {
+    "AAA BBB 1234567890123456789012345678901234567890123456789012345678901234567890",
+    NULL };
+
+const char* additional_rules_test_case_bad_03[] = {
+    "~PUBLIC_PATH~ ~PUBLIC_PATH~ rw",
+    NULL };
+
+const char* additional_rules_test_case_bad_04[] = {
+    "~ALL_APPS~ ~ALL_APPS~ wax",
+    NULL };
+
+const char* additional_rules_test_case_bad_05[] = {
+    "~ALL_APPS~ ~costam r",
+    NULL };
+
+const char* additional_rules_test_case_bad_06[] = {
+    "~AAA ~BBB tlw",
+    NULL };
+
+const char* additional_rules_test_case_good_01[] = {
+    "AAA BBB CCC",
+    NULL };
+
+const char* additional_rules_test_case_good_02[] = {
+    "qazapp1 ~PUBLIC_PATH~ r",
+    "~PUBLIC_PATH~ wsxapp2 w",
+    "qazapp3 ~GROUP_PATH~ x",
+    "~GROUP_PATH~ wsxapp4 t",
+    "qazapp5 ~SETTINGS_PATH~ a",
+    "~SETTINGS_PATH~ wsxapp6 l",
+    "qazapp7 ~NPRUNTIME_PATH~ rwxatl",
+    "~NPRUNTIME_PATH~ wsxapp8 ------",
+    "qazapp9 ~ALL_APPS~ rwx",
+    "~ALL_APPS~ wsxapp10 rwx",
+    "qazapp11 ~ALL_APPS_WITH_SAME_PERMISSION~ rwxt",
+    "~ALL_APPS_WITH_SAME_PERMISSION~ wsxapp12 rwxt",
+    NULL };
+
+const char* additional_rules_test_case_good_03[] = {
+    "~ALL_APPS~ costam wata",
+    NULL };
+
+void test_one_additional_rules_set(const char** rules)
+{
+    int result = -1;
+    additional_rules parsed_rules;
+
+// Parse rules and check if they are valid
+    bool correct_rules = additional_rules_parse(rules, parsed_rules);
+
+// Apply known set of additional rules and close db transaction to apply them to smack
+    DB_BEGIN
+    result = perm_add_additional_rules(additional_rules_rollback);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS,
+                         "Failed on applying rollback additional rules with result = " << result);
+    DB_END
+
+// Try setting test set
+    DB_BEGIN
+    result = perm_add_additional_rules(rules);
+    DB_END
+
+    if (correct_rules) {
+// If rules are correct test set should be applied succesfully
+        RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS,
+                             "perm_add_additional_rules failed. result = " << result);
+
+        //testing database
+        TestLibPrivilegeControlDatabase db_test;
+        db_test.test_db_after__perm_add_additional_rules(parsed_rules);
+    } else {
+// If rules are not valid test set should not be applied and db should rollback to known set
+        RUNNER_ASSERT_MSG_BT(result != PC_OPERATION_SUCCESS,
+                             "perm_add_additional_rules succeeded, but shouldn't.");
+
+        //testing rollback
+        additional_rules parsed_rollback_rules;
+        additional_rules_parse(additional_rules_rollback, parsed_rollback_rules);
+        TestLibPrivilegeControlDatabase db_test;
+        db_test.test_db_after__perm_add_additional_rules(parsed_rollback_rules);
+    }
+}
+
+RUNNER_TEST(privilege_control26_perm_add_additional_rules_database)
+{
+    UNUSED RestoreAdditionalRulesGuard guard;
+    test_one_additional_rules_set(additional_rules_empty);
+    test_one_additional_rules_set(additional_rules_rollback);
+
+    test_one_additional_rules_set(additional_rules_test_case_bad_01);
+    test_one_additional_rules_set(additional_rules_test_case_bad_02);
+    test_one_additional_rules_set(additional_rules_test_case_bad_03);
+    test_one_additional_rules_set(additional_rules_test_case_bad_04);
+    test_one_additional_rules_set(additional_rules_test_case_bad_05);
+    test_one_additional_rules_set(additional_rules_test_case_bad_06);
+
+    test_one_additional_rules_set(additional_rules_test_case_good_01);
+    test_one_additional_rules_set(additional_rules_test_case_good_02);
+    test_one_additional_rules_set(additional_rules_test_case_good_03);
+}
+
+/**************************************************************************************************/
+
+struct smack_rule
+{
+    std::string subject;
+    std::string object;
+    std::string access;
+};
+
+typedef std::vector<smack_rule> smack_rules_vector;
+
+void test_one_smack_rule(const smack_rule& rule)
+{
+    int result;
+    bool pass;
+    const std::vector<std::string> access = {"r", "w", "x" ,"a", "t", "l"};
+    for (auto a = access.begin(); a != access.end(); ++a) {
+        result = smack_have_access(rule.subject.c_str(), rule.object.c_str(), a->c_str());
+
+        if (rule.access.find(*a) != std::string::npos)
+            pass = (result == 1);
+        else
+            pass = (result <= 0);
+
+        RUNNER_ASSERT_MSG_BT(pass, "rule = {" << rule.subject << "; " << rule.object << "; " <<
+                             rule.access << "}" << std::endl <<
+                             "access = " << *a << std::endl <<
+                             "result = " << result << std::endl);
+    }
+}
+
+void test_smack_rules_vector(const smack_rules_vector& rules)
+{
+    for (auto rule = rules.begin(); rule != rules.end(); ++rule)
+        test_one_smack_rule(*rule);
+}
+
+const std::string APP27_A = "APP27_A";
+const std::string APP27_B = "APP27_B";
+const std::string APP27_C = "APP27_C";
+const std::string APP27_D = "APP27_D";
+const std::string APP27_E = "APP27_E";
+const std::string APP27_F = "APP27_F";
+
+const std::string APP27_A_PUB = "/etc/smack/test_privilege_control_DIR/A_PUBLIC";
+const std::string APP27_D_PUB = "/etc/smack/test_privilege_control_DIR/D_PUBLIC";
+const std::string APP27_E_PUB = "/etc/smack/test_privilege_control_DIR/E_PUBLIC";
+
+const std::string APP27_A_PUB_ID = smack_label_for_path(APP27_A, APP27_A_PUB);
+const std::string APP27_D_PUB_ID = smack_label_for_path(APP27_D, APP27_D_PUB);
+const std::string APP27_E_PUB_ID = smack_label_for_path(APP27_E, APP27_E_PUB);
+
+const std::string APP27_B_SET = "/etc/smack/test_privilege_control_DIR/B_SETTINGS";
+const std::string APP27_C_SET = "/etc/smack/test_privilege_control_DIR/C_SETTINGS";
+const std::string APP27_E_SET = "/etc/smack/test_privilege_control_DIR/E_SETTINGS";
+
+const std::string APP27_B_SET_ID = smack_label_for_path(APP27_B, APP27_B_SET);
+const std::string APP27_C_SET_ID = smack_label_for_path(APP27_C, APP27_C_SET);
+const std::string APP27_E_SET_ID = smack_label_for_path(APP27_E, APP27_E_SET);
+
+const std::string APP27_A_GRP = "/etc/smack/test_privilege_control_DIR/A_GROUP";
+const std::string APP27_B_GRP = "/etc/smack/test_privilege_control_DIR/B_GROUP";
+const std::string APP27_F_GRP = "/etc/smack/test_privilege_control_DIR/F_GROUP";
+
+const std::string APP27_A_GRP_ID = "A";
+const std::string APP27_B_GRP_ID = "B";
+const std::string APP27_F_GRP_ID = "F";
+
+const smack_rules_vector initial_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rx" },
+    { APP27_E, APP27_A_PUB_ID, "rx" },
+    { APP27_F, APP27_A_PUB_ID, "" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rx" },
+    { APP27_F, APP27_D_PUB_ID, "" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector rules_1_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rxl" },
+    { APP27_E, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_A_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_D_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "ra" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "ra" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "ra" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "xl" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "ra" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector add_app_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rxl" },
+    { APP27_E, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_A_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_D_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "ra" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "ra" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "ra" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "rwxatl" },
+
+    { APP27_A, APP27_B_SET_ID, "ra" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "xl" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "ra" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector add_dir_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rxl" },
+    { APP27_E, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_A_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_D_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_E_PUB_ID, "rx" },
+    { APP27_B, APP27_E_PUB_ID, "rx" },
+    { APP27_C, APP27_E_PUB_ID, "rx" },
+    { APP27_D, APP27_E_PUB_ID, "rxl" },
+    { APP27_E, APP27_E_PUB_ID, "rwxatl" },
+    { APP27_F, APP27_E_PUB_ID, "rwxatl" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "ra" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_F_GRP_ID, "ra" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "ra" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "xl" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "ra" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "rwxatl" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "xl" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "ra" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector rules_2_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rxlt" },
+    { APP27_D, APP27_A_PUB_ID, "rxa" },
+    { APP27_E, APP27_A_PUB_ID, "rwxl" },
+    { APP27_F, APP27_A_PUB_ID, "" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rxlt" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rwxl" },
+    { APP27_F, APP27_D_PUB_ID, "" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector rules_3_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rx" },
+    { APP27_E, APP27_A_PUB_ID, "rx" },
+    { APP27_F, APP27_A_PUB_ID, "" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rx" },
+    { APP27_F, APP27_D_PUB_ID, "" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "xlt" },
+    { APP27_D, APP27_A_GRP_ID, "" },
+    { APP27_E, APP27_A_GRP_ID, "rwl" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "" },
+    { APP27_E, APP27_B_GRP_ID, "rwl" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "" },
+    { APP27_B, APP27_E_SET_ID, "" },
+    { APP27_C, APP27_E_SET_ID, "" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const smack_rules_vector rules_4_state = {
+    { APP27_A, APP27_A_PUB_ID, "rwxatl" },
+    { APP27_B, APP27_A_PUB_ID, "rx" },
+    { APP27_C, APP27_A_PUB_ID, "rx" },
+    { APP27_D, APP27_A_PUB_ID, "rx" },
+    { APP27_E, APP27_A_PUB_ID, "rx" },
+    { APP27_F, APP27_A_PUB_ID, "" },
+
+    { APP27_A, APP27_D_PUB_ID, "rx" },
+    { APP27_B, APP27_D_PUB_ID, "rx" },
+    { APP27_C, APP27_D_PUB_ID, "rx" },
+    { APP27_D, APP27_D_PUB_ID, "rwxatl" },
+    { APP27_E, APP27_D_PUB_ID, "rx" },
+    { APP27_F, APP27_D_PUB_ID, "" },
+
+    { APP27_A, APP27_E_PUB_ID, "" },
+    { APP27_B, APP27_E_PUB_ID, "" },
+    { APP27_C, APP27_E_PUB_ID, "" },
+    { APP27_D, APP27_E_PUB_ID, "" },
+    { APP27_E, APP27_E_PUB_ID, "" },
+    { APP27_F, APP27_E_PUB_ID, "" },
+
+    { APP27_A, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_B, APP27_A_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_A_GRP_ID, "" },
+    { APP27_D, APP27_A_GRP_ID, "" },
+    { APP27_E, APP27_A_GRP_ID, "" },
+    { APP27_F, APP27_A_GRP_ID, "" },
+
+    { APP27_A, APP27_B_GRP_ID, "" },
+    { APP27_B, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_C, APP27_B_GRP_ID, "rwxatl" },
+    { APP27_D, APP27_B_GRP_ID, "" },
+    { APP27_E, APP27_B_GRP_ID, "" },
+    { APP27_F, APP27_B_GRP_ID, "" },
+
+    { APP27_A, APP27_F_GRP_ID, "" },
+    { APP27_B, APP27_F_GRP_ID, "" },
+    { APP27_C, APP27_F_GRP_ID, "" },
+    { APP27_D, APP27_F_GRP_ID, "" },
+    { APP27_E, APP27_F_GRP_ID, "" },
+    { APP27_F, APP27_F_GRP_ID, "" },
+
+    { APP27_A, APP27_B_SET_ID, "" },
+    { APP27_B, APP27_B_SET_ID, "rwxatl" },
+    { APP27_C, APP27_B_SET_ID, "xlt" },
+    { APP27_D, APP27_B_SET_ID, "" },
+    { APP27_E, APP27_B_SET_ID, "rwl" },
+    { APP27_F, APP27_B_SET_ID, "" },
+
+    { APP27_A, APP27_C_SET_ID, "" },
+    { APP27_B, APP27_C_SET_ID, "" },
+    { APP27_C, APP27_C_SET_ID, "" },
+    { APP27_D, APP27_C_SET_ID, "" },
+    { APP27_E, APP27_C_SET_ID, "" },
+    { APP27_F, APP27_C_SET_ID, "" },
+
+    { APP27_A, APP27_E_SET_ID, "" },
+    { APP27_B, APP27_E_SET_ID, "ra" },
+    { APP27_C, APP27_E_SET_ID, "xlt" },
+    { APP27_D, APP27_E_SET_ID, "" },
+    { APP27_E, APP27_E_SET_ID, "rwxatl" },
+    { APP27_F, APP27_E_SET_ID, "" }
+};
+
+const std::vector<std::string> directories_27 = { APP27_A_PUB, APP27_D_PUB, APP27_E_PUB,
+                                                  APP27_B_SET, APP27_C_SET, APP27_E_SET,
+                                                  APP27_A_GRP, APP27_B_GRP, APP27_F_GRP};
+
+void additional_rules_prepare_directories(void)
+{
+    for (auto dir = directories_27.begin(); dir != directories_27.end(); ++dir) {
+        int result = mkdir(dir->c_str(), 0);
+        RUNNER_ASSERT_MSG_BT(result == 0 || (result == -1 && errno == EEXIST), "directory = " <<
+                             dir->c_str() << "; result = " << result << "; errno  = " << errno <<
+                             "; error = " << strerror(errno));
+    }
+}
+
+void additional_rules_set_initial_state(void)
+{
+    int result;
+
+    DB_BEGIN
+    result = perm_app_install(APP27_A.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_A.c_str(), APP27_A_PUB.c_str(), PERM_APP_PATH_PUBLIC);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_A.c_str(), APP27_A_GRP.c_str(), PERM_APP_PATH_GROUP, "A");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_install(APP27_B.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_B.c_str(), APP27_A_GRP.c_str(), PERM_APP_PATH_GROUP, "A");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_B.c_str(), APP27_B_GRP.c_str(), PERM_APP_PATH_GROUP, "B");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_B.c_str(), APP27_B_SET.c_str(), PERM_APP_PATH_SETTINGS);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_install(APP27_C.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_C.c_str(), APP27_B_GRP.c_str(), PERM_APP_PATH_GROUP, "B");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_install(APP27_D.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_D.c_str(), APP27_D_PUB.c_str(), PERM_APP_PATH_PUBLIC);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_install(APP27_E.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_E.c_str(), APP27_E_SET.c_str(), PERM_APP_PATH_SETTINGS);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    DB_END
+}
+
+void additional_rules_set_add_app_state(void)
+{
+    int result;
+
+    DB_BEGIN
+    result = perm_app_setup_path(APP27_A.c_str(), APP27_F_GRP.c_str(), PERM_APP_PATH_GROUP, "F");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_install(APP27_F.c_str());
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_F.c_str(), APP27_F_GRP.c_str(), PERM_APP_PATH_GROUP, "F");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    DB_END
+}
+
+void additional_rules_set_add_dir_state(void)
+{
+    int result;
+
+    DB_BEGIN
+    result = perm_app_setup_path(APP27_E.c_str(), APP27_E_PUB.c_str(), PERM_APP_PATH_PUBLIC);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_setup_path(APP27_A.c_str(), APP27_B_GRP.c_str(), PERM_APP_PATH_GROUP, "B");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_C.c_str(), APP27_F_GRP.c_str(), PERM_APP_PATH_GROUP, "F");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    result = perm_app_setup_path(APP27_D.c_str(), APP27_A_GRP.c_str(), PERM_APP_PATH_GROUP, "A");
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+
+    result = perm_app_setup_path(APP27_C.c_str(), APP27_C_SET.c_str(), PERM_APP_PATH_SETTINGS);
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+    DB_END
+}
+
+void free_null_term_tab(char** tab)
+{
+    int i = 0;
+    while(tab[i])
+        free(tab[i++]);
+}
+
+void set_rules_1_state(void)
+{
+    int result, i = 0;
+    const int count = 9;
+    char* rules[count] = {};
+    std::unique_ptr<char*, std::function<void(char**)> > rules_pointer(rules, free_null_term_tab);
+
+    result = asprintf(&rules[i++], "%s %s %s", APP27_B.c_str(), APP27_A_PUB_ID.c_str(), "rwx");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_C.c_str(), APP27_D_PUB_ID.c_str(), "rwxa");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_D.c_str(), "~PUBLIC_PATH~", "rxl");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_E.c_str(), "~PUBLIC_PATH~", "rwxat");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_F.c_str(), "~PUBLIC_PATH~", "rwxatl");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_D.c_str(), "~GROUP_PATH~", "ra");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_A.c_str(), "~SETTINGS_PATH~", "ra");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_E.c_str(), "~SETTINGS_PATH~", "xl");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    rules[i] = NULL;
+
+    DB_BEGIN
+    result = perm_add_additional_rules((const char**)rules);
+    DB_END
+
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+}
+
+void set_rules_2_state(void)
+{
+    int result, i = 0;
+    const int count = 5;
+    char* rules[count] = {};
+    std::unique_ptr<char*, std::function<void(char**)> > rules_pointer(rules, free_null_term_tab);
+
+    result = asprintf(&rules[i++], "%s %s %s", APP27_B.c_str(), "~PUBLIC_PATH~", "r");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_C.c_str(), "~PUBLIC_PATH~", "lt");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_D.c_str(), "~PUBLIC_PATH~", "xa");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_E.c_str(), "~PUBLIC_PATH~", "w");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    rules[i] = NULL;
+
+    DB_BEGIN
+    result = perm_add_additional_rules((const char**) rules);
+    DB_END
+
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+}
+
+void set_rules_3_state(void)
+{
+    int result, i = 0;
+    const int count = 4;
+    char* rules[count] = {};
+    std::unique_ptr<char*, std::function<void(char**)> > rules_pointer(rules, free_null_term_tab);
+
+    result = asprintf(&rules[i++], "%s %s %s", APP27_B.c_str(), "~GROUP_PATH~", "ra");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_C.c_str(), "~GROUP_PATH~", "xlt");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_E.c_str(), "~GROUP_PATH~", "rw");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    rules[i] = NULL;
+
+    DB_BEGIN
+    result = perm_add_additional_rules((const char**) rules);
+    DB_END
+
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+}
+
+void set_rules_4_state(void)
+{
+    int result, i = 0;
+    const int count = 4;
+    char* rules[count] = {};
+    std::unique_ptr<char*, std::function<void(char**)> > rules_pointer(rules, free_null_term_tab);
+
+    result = asprintf(&rules[i++], "%s %s %s", APP27_B.c_str(), "~SETTINGS_PATH~", "ra");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_C.c_str(), "~SETTINGS_PATH~", "xlt");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    result = asprintf(&rules[i++], "%s %s %s", APP27_E.c_str(), "~SETTINGS_PATH~", "rw");
+    RUNNER_ASSERT_MSG_BT(result > 0, "asprintf failed");
+    rules[i] = NULL;
+
+    DB_BEGIN
+    result = perm_add_additional_rules((const char**) rules);
+    DB_END
+
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+}
+
+void cleanup_additional_rules_apps(void)
+{
+    int result;
+    const std::vector<std::string> apps = { APP27_A, APP27_B, APP27_C, APP27_D, APP27_E, APP27_F };
+
+    DB_BEGIN
+    for (auto a = apps.begin(); a != apps.end(); ++a) {
+        result = perm_app_uninstall(a->c_str());
+        RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "app = " << a->c_str() <<
+                             "; result = " << result);
+    }
+    DB_END
+}
+
+void cleanup_additional_rules_rules(void)
+{
+    int result;
+    const char* empty[] = { NULL };
+    DB_BEGIN
+    result = perm_add_additional_rules(empty);
+    DB_END
+    RUNNER_ASSERT_MSG_BT(result == PC_OPERATION_SUCCESS, "result = " << result);
+}
+
+void cleanup_additional_rules_directories(void)
+{
+    for (auto dir = directories_27.begin(); dir != directories_27.end(); ++dir) {
+        int result = rmdir(dir->c_str());
+        RUNNER_ASSERT_MSG_BT(result == 0 || (result == -1 && errno == ENOENT),
+                             "directory = " << dir->c_str() << "; result = " << result <<
+                             "; errno  = " << errno << "; error = " << strerror(errno));
+    }
+}
+
+void cleanup_additional_rules_all(void)
+{
+    cleanup_additional_rules_apps();
+    cleanup_additional_rules_rules();
+    additional_rules_prepare_directories();
+}
+
+RUNNER_TEST(privilege_control27_perm_add_additional_rules_smack_access_1_rollback)
+{
+    UNUSED RestoreAdditionalRulesGuard guard;
+    cleanup_additional_rules_all();
+
+    //initial state
+    additional_rules_set_initial_state();
+    test_smack_rules_vector(initial_state);
+
+    //set state with some public additional rules
+    set_rules_1_state();
+    test_smack_rules_vector(rules_1_state);
+
+    //rollback to initial state
+    cleanup_additional_rules_rules();
+    test_smack_rules_vector(initial_state);
+
+    //cleanup
+    cleanup_additional_rules_all();
+}
+
+RUNNER_TEST(privilege_control27_perm_add_additional_rules_smack_access_2_add_app)
+{
+    UNUSED RestoreAdditionalRulesGuard guard;
+    cleanup_additional_rules_all();
+
+    //initial state
+    additional_rules_set_initial_state();
+    test_smack_rules_vector(initial_state);
+
+    //set state with some public additional rules
+    set_rules_1_state();
+    test_smack_rules_vector(rules_1_state);
+
+    //add app F
+    additional_rules_set_add_app_state();
+    test_smack_rules_vector(add_app_state);
+
+    //cleanup
+    cleanup_additional_rules_all();
+}
+
+RUNNER_TEST(privilege_control27_perm_add_additional_rules_smack_access_3_add_dir)
+{
+    UNUSED RestoreAdditionalRulesGuard guard;
+    cleanup_additional_rules_all();
+
+    //initial state
+    additional_rules_set_initial_state();
+    test_smack_rules_vector(initial_state);
+
+    //set state with some public additional rules
+    set_rules_1_state();
+    test_smack_rules_vector(rules_1_state);
+
+    //add public dir E
+    additional_rules_set_add_dir_state();
+    test_smack_rules_vector(add_dir_state);
+
+    //cleanup
+    cleanup_additional_rules_all();
+}
+
+RUNNER_TEST(privilege_control27_perm_add_additional_rules_smack_access_4_update_rules)
+{
+    UNUSED RestoreAdditionalRulesGuard guard;
+    cleanup_additional_rules_all();
+
+    //initial state
+    additional_rules_set_initial_state();
+    test_smack_rules_vector(initial_state);
+
+    //set state with some additional rules
+    set_rules_1_state();
+    test_smack_rules_vector(rules_1_state);
+
+    //set state with some public additional rules
+    set_rules_2_state();
+    test_smack_rules_vector(rules_2_state);
+
+    //set state with some group additional rules
+    set_rules_3_state();
+    test_smack_rules_vector(rules_3_state);
+
+    //set state with some settings additional rules
+    set_rules_4_state();
+    test_smack_rules_vector(rules_4_state);
+
+    //cleanup
+    cleanup_additional_rules_all();
+}