45bab516ab4f1c6c51a1e78be95707cee61dae74
[platform/core/security/security-manager.git] / src / server / service / 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 #include <smack-common.h>
38
39 #include "security-manager.h"
40 #include "smack-labels.h"
41
42 namespace SecurityManager {
43
44 /* Const defined below is used to label links to executables */
45 const char *const LABEL_FOR_PUBLIC_APP_PATH = "User";
46
47 enum class FileDecision {
48     SKIP = 0,
49     LABEL = 1,
50     ERROR = -1
51 };
52
53 typedef std::function<FileDecision(const FTSENT*)> LabelDecisionFn;
54
55 static FileDecision labelAll(const FTSENT *ftsent __attribute__((unused)))
56 {
57     return FileDecision::LABEL;
58 }
59
60 static FileDecision labelDirs(const FTSENT *ftsent)
61 {
62     // label only directories
63     if (S_ISDIR(ftsent->fts_statp->st_mode))
64         return FileDecision::LABEL;
65     return FileDecision::SKIP;
66 }
67
68 static FileDecision labelExecs(const FTSENT *ftsent)
69 {
70     // LogDebug("Mode = " << ftsent->fts_statp->st_mode); // this could be helpfull in debugging
71     // label only regular executable files
72     if (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR))
73         return FileDecision::LABEL;
74     return FileDecision::SKIP;
75 }
76
77 static bool dirSetSmack(const std::string &path, const std::string &label,
78         const char *xattr_name, LabelDecisionFn fn)
79 {
80     char *const path_argv[] = {const_cast<char *>(path.c_str()), NULL};
81     FTSENT *ftsent;
82     FileDecision ret;
83
84     std::unique_ptr<FTS, std::function<void(FTS*)> > fts(
85             fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL),
86             fts_close);
87
88     if (fts.get() == NULL) {
89         LogError("fts_open failed.");
90         return false;
91     }
92
93     while ((ftsent = fts_read(fts.get())) != NULL) {
94         /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
95         if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
96             LogError("FTS_ERR error or failed stat(2) (FTS_NS)");
97             return false;
98         }
99
100         /* avoid to tag directories two times */
101         if (ftsent->fts_info == FTS_D)
102             continue;
103
104         ret = fn(ftsent);
105         if (ret == FileDecision::ERROR) {
106             LogError("fn(ftsent) failed.");
107             return false;
108         }
109
110         if (ret == FileDecision::LABEL) {
111             if (lsetxattr(ftsent->fts_path, xattr_name, label.c_str(), label.length(), 0) != 0) {
112                 LogError("lsetxattr failed.");
113                 return false;
114             }
115         }
116
117     }
118
119     /* If last call to fts_read() set errno, we need to return error. */
120     if ((errno != 0) && (ftsent == NULL)) {
121         LogError("Last errno from fts_read: " << strerror(errno));
122         return false;
123     }
124     return true;
125 }
126
127
128 static bool labelDir(const std::string &path, const std::string &label,
129         bool set_transmutable, bool set_executables)
130 {
131     bool ret = true;
132
133     // setting access label on everything in given directory and below
134     ret = dirSetSmack(path, label, XATTR_NAME_SMACK, labelAll);
135     if (!ret) {
136         LogError("dirSetSmack failed (access label)");
137         return ret;
138     }
139
140     if (set_transmutable) {
141         // setting transmute on dirs
142         ret = dirSetSmack(path, "TRUE", XATTR_NAME_SMACKTRANSMUTE, labelDirs);
143         if (!ret) {
144             LogError("dirSetSmack failed (transmute)");
145             return ret;
146         }
147     }
148
149     if (set_executables) {
150         ret = dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs);
151         if (!ret)
152         {
153             LogError("dirSetSmack failed (execs).");
154             return ret;
155         }
156     }
157
158     return ret;
159 }
160
161 bool setupPath(const std::string &pkgId, const std::string &path,
162     app_install_path_type pathType)
163 {
164     std::string label;
165     bool label_executables, label_transmute;
166
167     switch (pathType) {
168     case SECURITY_MANAGER_PATH_PRIVATE:
169         if (!generateAppLabel(pkgId, label))
170             return false;
171         label_executables = true;
172         label_transmute = false;
173         break;
174     case SECURITY_MANAGER_PATH_PUBLIC:
175         label.assign(LABEL_FOR_PUBLIC_APP_PATH);
176         label_executables = false;
177         label_transmute = true;
178         break;
179     case SECURITY_MANAGER_PATH_PUBLIC_RO:
180         label.assign("_");
181         label_executables = false;
182         label_transmute = false;
183         break;
184     default:
185         LogError("Path type not known.");
186         return false;
187     }
188     return labelDir(path, label, label_transmute, label_executables);
189 }
190
191 } // namespace SecurityManager