2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Rafal Krypa <r.krypa@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * @file smack-rules.cpp
20 * @author Jacek Bukarewicz <j.bukarewicz@samsung.com>
22 * @brief Implementation of a class managing smack rules
27 #include <sys/types.h>
29 #include <sys/smack.h>
33 #include <dpl/log/log.h>
35 #include "smack-rules.h"
36 #include "security-manager-common.h"
38 namespace SecurityManager {
40 const char *const SMACK_APP_LABEL_TEMPLATE = "~APP~";
41 const char *const APP_RULES_TEMPLATE_FILE_PATH = "/etc/smack/app-rules-template.smack";
42 const char *const APP_RULES_DIRECTORY = "/etc/smack/accesses.d/";
44 SmackRules::SmackRules()
46 if (smack_accesses_new(&m_handle) < 0) {
47 LogError("Failed to create smack_accesses handle");
48 throw std::bad_alloc();
52 SmackRules::~SmackRules() {
53 smack_accesses_free(m_handle);
56 bool SmackRules::add(const std::string &subject, const std::string &object,
57 const std::string &permissions)
59 return 0 == smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str());
62 bool SmackRules::clear() const
64 return 0 == smack_accesses_clear(m_handle);
67 bool SmackRules::apply() const
69 return 0 == smack_accesses_apply(m_handle);
72 bool SmackRules::loadFromFile(const std::string &path)
77 fd = open(path.c_str(), O_RDONLY);
79 LogError("Failed to open file: %s" << path);
83 if (smack_accesses_add_from_file(m_handle, fd)) {
84 LogError("Failed to load smack rules from file: %s" << path);
92 bool SmackRules::saveToFile(const std::string &path) const
97 fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
99 LogError("Failed to create file: %s" << path);
103 if (smack_accesses_save(m_handle, fd)) {
104 LogError("Failed to save rules to file: %s" << path);
105 unlink(path.c_str());
114 bool SmackRules::addFromTemplateFile(const std::string &pkgId)
116 std::vector<std::string> templateRules;
118 std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH);
120 if (!templateRulesFile.is_open()) {
121 LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
125 while (std::getline(templateRulesFile, line)) {
126 templateRules.push_back(line);
129 if (templateRulesFile.bad()) {
130 LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
134 return addFromTemplate(templateRules, pkgId);
137 bool SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
138 const std::string &pkgId)
140 std::string tokens[3];
141 std::string &subject = tokens[0];
142 std::string &object = tokens[1];
143 std::string &permissions = tokens[2];
145 for (auto rule = templateRules.begin(); rule != templateRules.end(); ++rule) {
146 if (rule->length() == 0)
149 if (!tokenizeRule(*rule, tokens, sizeof(tokens) / sizeof(*tokens))) {
153 bool subjectIsTemplate = (subject == SMACK_APP_LABEL_TEMPLATE);
154 bool objectIsTemplate = (object == SMACK_APP_LABEL_TEMPLATE);
156 if (objectIsTemplate == subjectIsTemplate) {
157 LogError("Invalid rule template. Exactly one app label template expected: " << *rule);
161 if (subjectIsTemplate) {
162 if (!SecurityManager::generateAppLabel(pkgId, subject)) {
163 LogError("Failed to generate app label from pkgid: " << pkgId);
168 if (objectIsTemplate) {
169 if (!SecurityManager::generateAppLabel(pkgId, object)) {
170 LogError("Failed to generate app label from pkgid: " << pkgId);
175 if (!add(subject, object, permissions)) {
176 LogError("Failed to add rule: " << subject << " " << object << " " << permissions);
185 bool SmackRules::tokenizeRule(const std::string &rule, std::string tokens[], int size)
189 const char delimiters[] = " \t\n\r";
191 for (int i = 0; i < size; i++) {
192 startPos = rule.find_first_not_of(delimiters, endPos);
193 if (startPos == std::string::npos) {
194 LogError("Unexpected end of rule: " << rule);
198 endPos = rule.find_first_of(delimiters, startPos);
199 tokens[i] = rule.substr(startPos, endPos - startPos);
202 if (endPos != std::string::npos &&
203 rule.find_first_not_of(delimiters, endPos) != std::string::npos) {
204 LogError("Too many tokens found in rule: " << rule);
211 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
213 std::string path(APP_RULES_DIRECTORY);
215 path.append(".smack");
219 bool SmackRules::installPackageRules(const std::string &pkgId) {
221 SmackRules smackRules;
222 std::string path = getPackageRulesFilePath(pkgId);
224 if (!smackRules.addFromTemplateFile(pkgId)) {
225 LogError("Failed to load smack rules for pkgId " << pkgId);
229 if (smack_smackfs_path() != NULL && !smackRules.apply()) {
230 LogError("Failed to apply application rules to kernel");
234 if (!smackRules.saveToFile(path)) {
240 } catch (const std::bad_alloc &e) {
241 LogError("Out of memory while trying to install smack rules for pkgId " << pkgId);
246 bool SmackRules::uninstallPackageRules(const std::string &pkgId) {
247 std::string path = getPackageRulesFilePath(pkgId);
248 if (access(path.c_str(), F_OK) == -1) {
249 if (errno == ENOENT) {
250 LogWarning("Smack rules were not installed for pkgId: " << pkgId);
254 LogWarning("Cannot access smack rules path: " << path);
260 if (rules.loadFromFile(path)) {
261 if (smack_smackfs_path() != NULL && !rules.clear()) {
262 LogWarning("Failed to clear smack kernel rules for pkgId: " << pkgId);
263 // don't stop uninstallation
266 LogWarning("Failed to load rules from file: " << path);
267 // don't stop uninstallation
270 if (unlink(path.c_str()) == -1) {
271 LogError("Failed to remove smack rules file: " << path);
276 } catch (const std::bad_alloc &e) {
277 LogError("Out of memory while trying to uninstall smack rules for pkgId: " << pkgId);
282 } // namespace SecurityManager