Add smack-privilege parsing to PolicyConfiguration
[platform/core/test/security-tests.git] / src / security-manager-tests / common / policy_configuration.cpp
1 /*
2  * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include <fstream>
18 #include <regex>
19 #include <string>
20 #include <vector>
21 #include <stdexcept>
22
23 #include <grp.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <dpl/test/test_runner.h>
28 #include <dpl/test/test_runner_child.h>
29 #include <policy_configuration.h>
30
31 #define CONF_DIR "/usr/share/security-manager/policy/"
32 #define CONF_GROUP_FILE "privilege-group.list"
33 #define CONF_SYSTEMD_PRIVS_FILE "privilege-managed-by-systemd-for-daemons.list"
34 #define CONF_USER_TEMPLATE_FILE "usertype-%s.profile"
35
36 namespace SecurityManagerTest {
37
38 namespace {
39
40 PolicyConfiguration::SmackPrivRulesMap parsePrivilegeSmackList() {
41     constexpr char PRIVILEGE[] = "~PRIVILEGE~";
42     PolicyConfiguration::SmackPrivRulesMap privilegeRules;
43
44     std::ifstream templateFile(CONF_DIR "privilege-smack.list");
45
46     if (templateFile.fail())
47         return privilegeRules;
48
49     try {
50         std::string line;
51         while (getline(templateFile, line)) {
52             if (line.empty() || line[0] == '#')
53                 continue;
54
55             std::string privilege, label, rulesFileName;
56             std::istringstream stream(line);
57             stream >> privilege >> label >> rulesFileName;
58
59             if (rulesFileName == "default")
60                 rulesFileName = "priv-rules-default-template.smack";
61
62             std::ifstream rulesFile(std::string(CONF_DIR) + "privilege-mapping/" + rulesFileName);
63             std::string object, subject, access;
64             while (rulesFile >> subject >> object >> access) {
65                 if (object.empty() || subject.empty())
66                     throw std::runtime_error("Malformed rule");
67
68                 // ignore
69                 if (object.front() != '~' || subject.front() != '~')
70                     continue;
71
72                 if (object == PRIVILEGE)
73                     object = label;
74                 if (subject == PRIVILEGE)
75                     subject = label;
76                 privilegeRules[privilege].emplace_back(std::move(subject),
77                                                        std::move(object),
78                                                        std::move(access));
79             }
80         }
81     } catch (const std::exception&) {
82         privilegeRules.clear();
83     }
84     return privilegeRules;
85 }
86
87 } // namespace anonymous
88
89 gid_t nameToGid(const char *name) {
90     struct group entry, *gresult;
91     char buffer[1024];
92     RUNNER_ASSERT_MSG(
93         0 == getgrnam_r(name, &entry, buffer, 1024, &gresult) && (gresult != NULL),
94         "Error in getgrnam. Group name: " << name);
95     return entry.gr_gid;
96 }
97
98
99 std::string PolicyConfiguration::getConfigFilePath(UserType userType) {
100     const char *user = NULL;
101     switch(userType) {
102     case GUEST:  user = "guest"; break;
103     case NORMAL: user = "normal"; break;
104     case ADMIN:  user = "admin"; break;
105     case SYSTEM: user = "system"; break;
106     }
107     char buffer[1024];
108     snprintf(buffer, 1024, CONF_DIR CONF_USER_TEMPLATE_FILE, user);
109     return std::string(buffer);
110 }
111
112 PolicyConfiguration::PrivVector PolicyConfiguration::getUserPriv(PolicyConfiguration::UserType userType) {
113     return getUserDescription(userType).privVector;
114 }
115
116 PolicyConfiguration::GroupVector PolicyConfiguration::getUserGroup(PolicyConfiguration::UserType userType) {
117     return getUserDescription(userType).groupVector;
118 }
119
120 PolicyConfiguration::GidVector PolicyConfiguration::getUserGid(PolicyConfiguration::UserType userType) {
121     return getUserDescription(userType).gidVector;
122 }
123
124 PolicyConfiguration::GidVector PolicyConfiguration::getGid() {
125     return groupToGid(getGroup());
126 }
127
128 PolicyConfiguration::GroupVector PolicyConfiguration::getGroup() {
129     GroupVector result;
130     if (m_privGroupMap.empty())
131         loadPrivGroupMap();
132     for (auto &e : m_privGroupMap)
133         result.push_back(e.second);
134     return result;
135 }
136
137 PolicyConfiguration::UserDescription& PolicyConfiguration::getUserDescription(PolicyConfiguration::UserType userType) {
138     auto it = m_userDescriptionMap.find(userType);
139     if (it == m_userDescriptionMap.end())
140         m_userDescriptionMap[userType] = loadUserDescription(userType);
141     return m_userDescriptionMap[userType];
142 }
143
144 gid_t PolicyConfiguration::groupToGid(const std::string &gname) {
145     auto it = m_groupGidMap.find(gname);
146     if (it == m_groupGidMap.end())
147         m_groupGidMap[gname] = nameToGid(gname.c_str());
148     return m_groupGidMap[gname];
149 }
150
151 PolicyConfiguration::GidVector PolicyConfiguration::groupToGid(const PolicyConfiguration::GroupVector &groupVector) {
152     GidVector result;
153     for (auto &e : groupVector)
154         result.push_back(groupToGid(e));
155     return result;
156 }
157
158 PolicyConfiguration::PrivGroupMap PolicyConfiguration::getPrivGroupMap()
159 {
160     if (m_privGroupMap.empty())
161         loadPrivGroupMap();
162     return m_privGroupMap;
163 }
164
165 bool PolicyConfiguration::getIsAskuserEnabled() {
166 #ifdef ASKUSER_ENABLED
167     return true;
168 #else
169     return false;
170 #endif
171 }
172
173 PolicyConfiguration::UserDescription PolicyConfiguration::loadUserDescription(PolicyConfiguration::UserType userType) {
174     UserDescription result;
175     std::string path = getConfigFilePath(userType);
176     result.privVector = loadPrivFile(path);
177     result.groupVector = privToGroup(result.privVector);
178     result.gidVector = groupToGid(result.groupVector);
179     return result;
180 }
181
182 PolicyConfiguration::PrivVector PolicyConfiguration::loadPrivFile(const std::string &path) {
183     PrivVector result;
184     std::ifstream file(path);
185     std::string line;
186     std::regex r("^\\*[ \t]+(.*)");
187     while (std::getline(file, line)) {
188         std::smatch m;
189         if (std::regex_search(line, m, r))
190             result.push_back(m[1]);
191     }
192     return result;
193 }
194
195 PolicyConfiguration::PrivVector PolicyConfiguration::getSystemdManagedPrivs()
196 {
197     PolicyConfiguration::PrivVector result;
198     std::ifstream file(CONF_DIR CONF_SYSTEMD_PRIVS_FILE);
199     if (!file.is_open()) {
200         RUNNER_ASSERT_MSG(file.is_open(),
201           "Unable to read config file " << CONF_DIR CONF_SYSTEMD_PRIVS_FILE);
202     }
203     std::string line;
204     std::regex r("^(http(.*))");
205     while (std::getline(file, line)) {
206         std::smatch m;
207         if (std::regex_search(line, m, r))
208             result.emplace_back(m[1]);
209     }
210     return result;
211 }
212
213 void PolicyConfiguration::loadPrivGroupMap(void) {
214     std::string pgPath(CONF_DIR CONF_GROUP_FILE);
215     std::ifstream file(pgPath);
216
217     RUNNER_ASSERT_MSG(file.is_open(),
218       "Unable to read group mapping file " << pgPath);
219
220     std::string line;
221     std::regex r("^(http(.*)) +(.*)");
222     while (std::getline(file, line)) {
223         std::smatch m;
224         if (std::regex_search(line, m, r))
225             m_privGroupMap[m[1]] = m[3];
226     }
227 }
228
229 std::string PolicyConfiguration::getPkgRulesFilePath() {
230     return CONF_DIR "pkg-rules-template.smack";
231 }
232 std::string PolicyConfiguration::getAppRulesFilePath() {
233     return CONF_DIR "app-rules-template.smack";
234 }
235
236 const PolicyConfiguration::SmackPrivRulesMap& PolicyConfiguration::getSmackPrivRulesMap() {
237     const static auto smackPrivRulesMap = parsePrivilegeSmackList();
238     return smackPrivRulesMap;
239 }
240
241 } // namespace SecurityManagerTest
242