Add smackfs check to Installer service.
[platform/core/security/security-manager.git] / src / server / service / 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
33 #include <dpl/log/log.h>
34
35 #include "smack-rules.h"
36 #include "security-manager-common.h"
37
38 namespace SecurityManager {
39
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/";
43
44 SmackRules::SmackRules()
45 {
46     if (smack_accesses_new(&m_handle) < 0) {
47         LogError("Failed to create smack_accesses handle");
48         throw std::bad_alloc();
49     }
50 }
51
52 SmackRules::~SmackRules() {
53     smack_accesses_free(m_handle);
54 }
55
56 bool SmackRules::add(const std::string &subject, const std::string &object,
57         const std::string &permissions)
58 {
59     return 0 == smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str());
60 }
61
62 bool SmackRules::clear() const
63 {
64     return 0 == smack_accesses_clear(m_handle);
65 }
66
67 bool SmackRules::apply() const
68 {
69     return 0 == smack_accesses_apply(m_handle);
70 }
71
72 bool SmackRules::loadFromFile(const std::string &path)
73 {
74     int fd;
75     bool ret = true;
76
77     fd = open(path.c_str(), O_RDONLY);
78     if (fd == -1) {
79         LogError("Failed to open file: %s" << path);
80         return false;
81     }
82
83     if (smack_accesses_add_from_file(m_handle, fd)) {
84         LogError("Failed to load smack rules from file: %s" << path);
85         ret = false;
86     }
87
88     close(fd);
89     return ret;
90 }
91
92 bool SmackRules::saveToFile(const std::string &path) const
93 {
94     int fd;
95     bool ret = true;
96
97     fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
98     if (fd == -1) {
99         LogError("Failed to create file: %s" << path);
100         return false;
101     }
102
103     if (smack_accesses_save(m_handle, fd)) {
104         LogError("Failed to save rules to file: %s" << path);
105         unlink(path.c_str());
106         ret = false;
107     }
108
109     close(fd);
110     return ret;
111 }
112
113
114 bool SmackRules::addFromTemplateFile(const std::string &pkgId)
115 {
116     std::vector<std::string> templateRules;
117     std::string line;
118     std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH);
119
120     if (!templateRulesFile.is_open()) {
121         LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
122         return false;
123     }
124
125     while (std::getline(templateRulesFile, line)) {
126         templateRules.push_back(line);
127     }
128
129     if (templateRulesFile.bad()) {
130         LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
131         return false;
132     }
133
134     return addFromTemplate(templateRules, pkgId);
135 }
136
137 bool SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
138         const std::string &pkgId)
139 {
140     std::string tokens[3];
141     std::string &subject = tokens[0];
142     std::string &object = tokens[1];
143     std::string &permissions = tokens[2];
144
145     for (auto rule = templateRules.begin(); rule != templateRules.end(); ++rule) {
146         if (rule->length() == 0)
147             continue;
148
149         if (!tokenizeRule(*rule, tokens, sizeof(tokens) / sizeof(*tokens))) {
150             return false;
151         }
152
153         bool subjectIsTemplate = (subject == SMACK_APP_LABEL_TEMPLATE);
154         bool objectIsTemplate = (object == SMACK_APP_LABEL_TEMPLATE);
155
156         if (objectIsTemplate == subjectIsTemplate) {
157             LogError("Invalid rule template. Exactly one app label template expected: " << *rule);
158             return false;
159         }
160
161         if (subjectIsTemplate) {
162             if (!SecurityManager::generateAppLabel(pkgId, subject)) {
163                 LogError("Failed to generate app label from pkgid: " << pkgId);
164                 return false;
165             }
166         }
167
168         if (objectIsTemplate) {
169             if (!SecurityManager::generateAppLabel(pkgId, object)) {
170                 LogError("Failed to generate app label from pkgid: " << pkgId);
171                 return false;
172             }
173         }
174
175         if (!add(subject, object, permissions)) {
176             LogError("Failed to add rule: " << subject << " " << object << " " << permissions);
177             return false;
178         }
179     }
180
181     return true;
182 }
183
184
185 bool SmackRules::tokenizeRule(const std::string &rule, std::string tokens[], int size)
186 {
187     size_t startPos;
188     size_t endPos = 0;
189     const char delimiters[] = " \t\n\r";
190
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);
195             return false;
196         }
197
198         endPos = rule.find_first_of(delimiters, startPos);
199         tokens[i] = rule.substr(startPos, endPos - startPos);
200     }
201
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);
205         return false;
206     }
207
208     return true;
209 }
210
211 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
212 {
213     std::string path(APP_RULES_DIRECTORY);
214     path.append(pkgId);
215     path.append(".smack");
216     return path;
217 }
218
219 bool SmackRules::installPackageRules(const std::string &pkgId) {
220     try {
221          SmackRules smackRules;
222          std::string path = getPackageRulesFilePath(pkgId);
223
224          if (!smackRules.addFromTemplateFile(pkgId)) {
225              LogError("Failed to load smack rules for pkgId " << pkgId);
226              return false;
227          }
228
229          if (smack_smackfs_path() != NULL && !smackRules.apply()) {
230              LogError("Failed to apply application rules to kernel");
231              return false;
232          }
233
234          if (!smackRules.saveToFile(path)) {
235              smackRules.clear();
236              return false;
237          }
238
239          return true;
240      } catch (const std::bad_alloc &e) {
241          LogError("Out of memory while trying to install smack rules for pkgId " << pkgId);
242          return false;
243      }
244 }
245
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);
251             return true;
252         }
253
254         LogWarning("Cannot access smack rules path: " << path);
255         return false;
256     }
257
258     try {
259         SmackRules rules;
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
264             }
265         } else {
266             LogWarning("Failed to load rules from file: " << path);
267             // don't stop uninstallation
268         }
269
270         if (unlink(path.c_str()) == -1) {
271             LogError("Failed to remove smack rules file: " << path);
272             return false;
273         }
274
275         return true;
276     } catch (const std::bad_alloc &e) {
277         LogError("Out of memory while trying to uninstall smack rules for pkgId: " << pkgId);
278         return false;
279     }
280 }
281
282 } // namespace SecurityManager
283