d3bdf225d75c318e0637abed08ae18171500f01e
[platform/core/security/security-manager.git] / src / common / smack-rules.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18 /**
19  * @file        smack-rules.cpp
20  * @author      Jacek Bukarewicz <j.bukarewicz@samsung.com>
21  * @version     1.0
22  * @brief       Implementation of a class managing smack rules
23  *
24  */
25
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/smack.h>
30 #include <fcntl.h>
31 #include <fstream>
32 #include <cstring>
33 #include <sstream>
34 #include <memory>
35
36 #include <dpl/log/log.h>
37 #include <tzplatform_config.h>
38
39 #include "smack-labels.h"
40 #include "smack-rules.h"
41 #include "zone-utils.h"
42
43 namespace SecurityManager {
44
45 const char *const SMACK_APP_LABEL_TEMPLATE     = "~APP~";
46 const char *const SMACK_PKG_LABEL_TEMPLATE     = "~PKG~";
47 const char *const APP_RULES_TEMPLATE_FILE_PATH = tzplatform_mkpath4(TZ_SYS_SHARE, "security-manager", "policy", "app-rules-template.smack");
48 const char *const SMACK_APP_IN_PACKAGE_PERMS   = "rwxat";
49
50 SmackRules::SmackRules()
51 {
52     if (smack_accesses_new(&m_handle) < 0) {
53         LogError("Failed to create smack_accesses handle");
54         throw std::bad_alloc();
55     }
56 }
57
58 SmackRules::~SmackRules() {
59     smack_accesses_free(m_handle);
60 }
61
62 void SmackRules::add(const std::string &subject, const std::string &object,
63         const std::string &permissions)
64 {
65     if (smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str()))
66         ThrowMsg(SmackException::LibsmackError, "smack_accesses_add");
67 }
68
69 void SmackRules::addModify(const std::string &subject, const std::string &object,
70         const std::string &allowPermissions, const std::string &denyPermissions)
71 {
72     if (smack_accesses_add_modify(m_handle, subject.c_str(), object.c_str(), allowPermissions.c_str(), denyPermissions.c_str()))
73         ThrowMsg(SmackException::LibsmackError, "smack_accesses_add_modify");
74 }
75
76 void SmackRules::clear() const
77 {
78     if (smack_accesses_clear(m_handle))
79         ThrowMsg(SmackException::LibsmackError, "smack_accesses_clear");
80 }
81
82 void SmackRules::apply() const
83 {
84     if (smack_accesses_apply(m_handle))
85         ThrowMsg(SmackException::LibsmackError, "smack_accesses_apply");
86
87 }
88
89 void SmackRules::loadFromFile(const std::string &path)
90 {
91     int fd;
92
93     fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY));
94     if (fd == -1) {
95         LogError("Failed to open file: " << path);
96         ThrowMsg(SmackException::FileError, "Failed to open file: " << path);
97     }
98
99     if (smack_accesses_add_from_file(m_handle, fd)) {
100         LogError("Failed to load smack rules from file: " << path);
101         ThrowMsg(SmackException::LibsmackError, "Failed to load smack rules from file: " << path);
102     }
103
104     if (close(fd) == -1) {
105         // don't change the return code, the descriptor should be closed despite the error.
106         LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
107     }
108 }
109
110 void SmackRules::saveToFile(const std::string &path) const
111 {
112     int fd;
113
114     fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644));
115     if (fd == -1) {
116         LogError("Failed to create file: " << path);
117         ThrowMsg(SmackException::FileError, "Failed to create file: " << path);
118     }
119
120     if (smack_accesses_save(m_handle, fd)) {
121         LogError("Failed to save rules to file: " << path);
122         unlink(path.c_str());
123         ThrowMsg(SmackException::LibsmackError, "Failed to save rules to file: " << path);
124     }
125
126     if (close(fd) == -1) {
127         if (errno == EIO) {
128             LogError("I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
129             unlink(path.c_str());
130             ThrowMsg(SmackException::FileError, "I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
131         } else {
132             // non critical error
133             // don't change the return code, the descriptor should be closed despite the error.
134             LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
135         }
136     }
137 }
138
139
140 void SmackRules::addFromTemplateFile(const std::string &appId, const std::string &pkgId,
141         const std::string &zoneId)
142 {
143     std::vector<std::string> templateRules;
144     std::string line;
145     std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH);
146
147     if (!templateRulesFile.is_open()) {
148         LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
149         ThrowMsg(SmackException::FileError, "Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
150     }
151
152     while (std::getline(templateRulesFile, line)) {
153         templateRules.push_back(line);
154     }
155
156     if (templateRulesFile.bad()) {
157         LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
158         ThrowMsg(SmackException::FileError, "Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
159     }
160
161     addFromTemplate(templateRules, appId, pkgId, zoneId);
162 }
163
164 void SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
165         const std::string &appId, const std::string &pkgId, const std::string &zoneId)
166 {
167     for (auto rule : templateRules) {
168         if (rule.empty())
169             continue;
170
171         std::stringstream stream(rule);
172         std::string subject, object, permissions;
173         stream >> subject >> object >> permissions;
174
175         if (stream.fail() || !stream.eof()) {
176             LogError("Invalid rule template: " << rule);
177             ThrowMsg(SmackException::FileError, "Invalid rule template: " << rule);
178         }
179
180         if (subject == SMACK_APP_LABEL_TEMPLATE)
181             subject = SmackLabels::generateAppLabel(appId);
182
183         if (subject == SMACK_PKG_LABEL_TEMPLATE)
184             subject = SmackLabels::generatePkgLabel(pkgId);
185
186         if (object == SMACK_APP_LABEL_TEMPLATE)
187             object = SmackLabels::generateAppLabel(appId);
188
189         if (object == SMACK_PKG_LABEL_TEMPLATE)
190             object = SmackLabels::generatePkgLabel(pkgId);
191
192         if (!zoneId.empty()) {
193             // FIXME replace with vasum calls. See zone-utils.h
194             subject = zoneSmackLabelGenerate(subject, zoneId);
195             object = zoneSmackLabelGenerate(object, zoneId);
196         }
197
198         add(subject, object, permissions);
199     }
200 }
201
202 void SmackRules::generatePackageCrossDeps(const std::vector<std::string> &pkgContents,
203         const std::string &zoneId)
204 {
205     LogDebug ("Generating cross-package rules");
206
207     std::string subjectLabel, objectLabel;
208     std::string appsInPackagePerms = SMACK_APP_IN_PACKAGE_PERMS;
209
210     for (const auto &subject : pkgContents) {
211         for (const auto &object : pkgContents) {
212             if (object == subject)
213                 continue;
214
215             subjectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(subject), zoneId);
216             objectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(object), zoneId);
217             LogDebug ("Trying to add rule subject: " << subjectLabel << " object: " << objectLabel << " perms: " << appsInPackagePerms);
218             add(subjectLabel, objectLabel, appsInPackagePerms);
219         }
220     }
221 }
222
223 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
224 {
225     std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("pkg_" + pkgId).c_str()));
226     return path;
227 }
228
229 std::string SmackRules::getApplicationRulesFilePath(const std::string &appId)
230 {
231     std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("app_" +  appId).c_str()));
232     return path;
233 }
234
235 void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
236         const std::vector<std::string> &pkgContents)
237 {
238     installApplicationRules(appId, pkgId, pkgContents, std::string());
239 }
240
241 void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
242         const std::vector<std::string> &pkgContents, const std::string &zoneId)
243 {
244     SmackRules smackRules;
245     std::string appPath = getApplicationRulesFilePath(appId);
246
247     smackRules.addFromTemplateFile(appId, pkgId, zoneId);
248
249     if (smack_smackfs_path() != NULL)
250         smackRules.apply();
251
252     smackRules.saveToFile(appPath);
253     updatePackageRules(pkgId, pkgContents, zoneId);
254 }
255
256 void SmackRules::updatePackageRules(const std::string &pkgId,
257         const std::vector<std::string> &pkgContents, const std::string &zoneId)
258 {
259     SmackRules smackRules;
260     std::string pkgPath = getPackageRulesFilePath(pkgId);
261
262     smackRules.generatePackageCrossDeps(pkgContents, zoneId);
263
264     if (smack_smackfs_path() != NULL)
265         smackRules.apply();
266
267     smackRules.saveToFile(pkgPath);
268 }
269
270 void SmackRules::uninstallPackageRules(const std::string &pkgId)
271 {
272     uninstallRules(getPackageRulesFilePath(pkgId));
273 }
274
275 void SmackRules::uninstallApplicationRules(const std::string &appId,
276         const std::string &pkgId, std::vector<std::string> pkgContents, const std::string &zoneId)
277 {
278     uninstallRules(getApplicationRulesFilePath(appId));
279     updatePackageRules(pkgId, pkgContents, zoneId);
280 }
281
282 void SmackRules::uninstallRules(const std::string &path)
283 {
284     if (access(path.c_str(), F_OK) == -1) {
285         if (errno == ENOENT) {
286             LogWarning("Smack rules not found in file: " << path);
287             return;
288         }
289
290         LogWarning("Cannot access smack rules path: " << path);
291         ThrowMsg(SmackException::FileError, "Cannot access smack rules path: " << path);
292     }
293
294     try {
295         SmackRules rules;
296         rules.loadFromFile(path);
297         if (smack_smackfs_path())
298             rules.clear();
299     } catch (const SmackException::Base &e) {
300         LogWarning("Failed to clear smack kernel rules from file: " << path);
301         // don't stop uninstallation
302     }
303
304     if (unlink(path.c_str()) == -1) {
305         LogWarning("Failed to remove smack rules file: " << path);
306         ThrowMsg(SmackException::FileError, "Failed to remove smack rules file: " << path);
307     }
308 }
309
310 } // namespace SecurityManager