New structure of application file paths
[platform/core/security/security-manager.git] / src / common / smack-labels.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-labels.cpp
20  * @author      Jan Cybulski <j.cybulski@samsung.com>
21  * @author      Rafal Krypa <r.krypa@samsung.com>
22  * @version     1.0
23  * @brief       Implementation of functions managing smack labels
24  *
25  */
26
27 #include <sys/stat.h>
28 #include <sys/smack.h>
29 #include <sys/xattr.h>
30 #include <linux/xattr.h>
31 #include <memory>
32 #include <fts.h>
33 #include <cstring>
34 #include <string>
35
36 #include <dpl/log/log.h>
37
38 #include "security-manager.h"
39 #include "smack-labels.h"
40
41 namespace SecurityManager {
42
43 /* Const defined below is used to label files accessible to apps only for reading */
44 const char *const LABEL_FOR_APP_RO_PATH = "User::Home";
45
46 enum class FileDecision {
47     SKIP = 0,
48     LABEL = 1,
49     ERROR = -1
50 };
51
52 typedef std::function<FileDecision(const FTSENT*)> LabelDecisionFn;
53
54 static FileDecision labelAll(const FTSENT *ftsent __attribute__((unused)))
55 {
56     return FileDecision::LABEL;
57 }
58
59 static FileDecision labelDirs(const FTSENT *ftsent)
60 {
61     // label only directories
62     if (S_ISDIR(ftsent->fts_statp->st_mode))
63         return FileDecision::LABEL;
64     return FileDecision::SKIP;
65 }
66
67 static FileDecision labelExecs(const FTSENT *ftsent)
68 {
69     // LogDebug("Mode = " << ftsent->fts_statp->st_mode); // this could be helpfull in debugging
70     // label only regular executable files
71     if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
72         return FileDecision::LABEL;
73     return FileDecision::SKIP;
74 }
75
76 static inline bool pathSetSmack(const char *path, const std::string &label,
77         const char *xattr_name)
78 {
79     if (lsetxattr(path, xattr_name, label.c_str(), label.length(), 0) != 0)
80         return false;
81
82     return true;
83 }
84
85 static bool dirSetSmack(const std::string &path, const std::string &label,
86         const char *xattr_name, LabelDecisionFn fn)
87 {
88     char *const path_argv[] = {const_cast<char *>(path.c_str()), NULL};
89     FTSENT *ftsent;
90     FileDecision ret;
91
92     std::unique_ptr<FTS, std::function<void(FTS*)> > fts(
93             fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL),
94             fts_close);
95
96     if (fts.get() == NULL) {
97         LogError("fts_open failed.");
98         return false;
99     }
100
101     while ((ftsent = fts_read(fts.get())) != NULL) {
102         /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
103         if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
104             LogError("FTS_ERR error or failed stat(2) (FTS_NS)");
105             return false;
106         }
107
108         /* avoid to tag directories two times */
109         if (ftsent->fts_info == FTS_D)
110             continue;
111
112         ret = fn(ftsent);
113         if (ret == FileDecision::ERROR) {
114             LogError("fn(ftsent) failed.");
115             return false;
116         }
117
118         if (ret == FileDecision::LABEL) {
119             if (!pathSetSmack(ftsent->fts_path, label, xattr_name)) {
120                 LogError("pathSetSmack failed.");
121                 return false;
122             }
123         }
124
125     }
126
127     /* If last call to fts_read() set errno, we need to return error. */
128     if ((errno != 0) && (ftsent == NULL)) {
129         LogError("Last errno from fts_read: " << strerror(errno));
130         return false;
131     }
132     return true;
133 }
134
135 static bool labelDir(const std::string &path, const std::string &label,
136         bool set_transmutable, bool set_executables)
137 {
138     bool ret = true;
139
140     // setting access label on everything in given directory and below
141     ret = dirSetSmack(path, label, XATTR_NAME_SMACK, labelAll);
142     if (!ret) {
143         LogError("dirSetSmack failed (access label)");
144         return ret;
145     }
146
147     if (set_transmutable) {
148         // setting transmute on dirs
149         ret = dirSetSmack(path, "TRUE", XATTR_NAME_SMACKTRANSMUTE, labelDirs);
150         if (!ret) {
151             LogError("dirSetSmack failed (transmute)");
152             return ret;
153         }
154     }
155
156     if (set_executables) {
157         ret = dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs);
158         if (!ret)
159         {
160             LogError("dirSetSmack failed (execs).");
161             return ret;
162         }
163     }
164
165     return ret;
166 }
167
168 bool setupPath(const std::string &appId, const std::string &path,
169     app_install_path_type pathType)
170 {
171     std::string label;
172     bool label_executables, label_transmute;
173
174     switch (pathType) {
175     case SECURITY_MANAGER_PATH_PRIVATE:
176     case SECURITY_MANAGER_PATH_RW:
177         if (!generateAppLabel(appId, label))
178             return false;
179         label_executables = true;
180         label_transmute = false;
181         break;
182     case SECURITY_MANAGER_PATH_PUBLIC:
183     case SECURITY_MANAGER_PATH_RO:
184         label.assign(LABEL_FOR_APP_RO_PATH);
185         label_executables = false;
186         label_transmute = true;
187         break;
188     case SECURITY_MANAGER_PATH_PUBLIC_RO:
189         label.assign("_");
190         label_executables = false;
191         label_transmute = false;
192         break;
193     default:
194         LogError("Path type not known.");
195         return false;
196     }
197     return labelDir(path, label, label_transmute, label_executables);
198 }
199
200 std::string generateAppNameFromLabel(const std::string &label)
201 {
202     //TODO: Fix when a label generating mechanism is ready
203     return label;
204 }
205
206 bool setupCorrectPath(const std::string &pkgId, const std::string &appId, const std::string &appPath)
207 {
208     std::string tmpPath;
209     std::string label;
210
211     tmpPath.clear();
212     tmpPath = appPath + "/" + pkgId;
213
214     label.clear();
215     generatePkgLabel(pkgId, label);
216
217     if (!pathSetSmack(tmpPath.c_str(), label, XATTR_NAME_SMACK)) {
218         LogError("pathSetSmack failed (access label) on: " << tmpPath);
219         return false;
220     }
221
222     label.clear();
223     generateAppLabel(appId, label);
224     tmpPath += "/" + appId;
225
226     if (!pathSetSmack(tmpPath.c_str(), label, XATTR_NAME_SMACK)) {
227         LogError("pathSetSmack failed (access label) on: " << tmpPath);
228         return false;
229     }
230
231     if (!pathSetSmack(tmpPath.c_str(), "TRUE", XATTR_NAME_SMACKTRANSMUTE)) {
232         LogError("pathSetSmack failed (transmute) on: " << tmpPath);
233         return false;
234     }
235
236     return true;
237 }
238
239 bool generateAppLabel(const std::string &appId, std::string &label)
240 {
241     (void) appId;
242     label = "User";
243     return true;
244 }
245
246 bool generatePkgLabel(const std::string &pkgId, std::string &label)
247 {
248     (void) pkgId;
249     label = "User";
250     return (true);
251 }
252
253 } // namespace SecurityManager