fc2f4f6169f589bcc5801568c3d512897a7c7845
[platform/core/security/cert-svc.git] / src / vcore / ReferenceValidator.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
18  *              Sangwan Kwon (sangwan.kwon@samsung.com)
19  * @file        ReferenceValidator.cpp
20  * @version     1.0
21  * @brief       Compare signature reference list and list of widget file.
22  */
23 #include <vcore/ReferenceValidator.h>
24
25 #include <dirent.h>
26 #include <errno.h>
27 #include <fstream>
28 #include <memory>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 #include <pcrecpp.h>
35
36 #include <dpl/log/log.h>
37
38 #ifndef PATH_MAX
39 #define PATH_MAX 4096
40 #endif
41
42 namespace {
43
44 const char *SPECIAL_SYMBOL_CURRENT_DIR = ".";
45 const char *SPECIAL_SYMBOL_UPPER_DIR = "..";
46 const char *SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE = "author-signature.xml";
47 const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^signature[1-9][0-9]*\\.xml";
48
49 const char MARK_ENCODED_CHAR = '%';
50
51 } // namespace anonymous
52
53 namespace ValidationCore {
54
55 class ReferenceValidator::Impl {
56 public:
57         Impl(const std::string &dirpath)
58                 : m_dirpath(dirpath)
59                 , m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE)
60         {}
61
62         virtual ~Impl() {}
63
64         Result checkReferences(const SignatureData &signatureData)
65         {
66                 const ReferenceSet &refSet = signatureData.getReferenceSet();
67                 ReferenceSet refDecoded;
68
69                 try {
70                         for (auto it = refSet.begin(); it != refSet.end(); ++it) {
71                                 if (std::string::npos != it->find(MARK_ENCODED_CHAR))
72                                         refDecoded.insert(decodeProcent(*it));
73                                 else
74                                         refDecoded.insert(*it);
75                         }
76                 } catch (Result &) {
77                         return ERROR_DECODING_URL;
78                 }
79
80                 return dfsCheckDirectories(
81                                    refDecoded,
82                                    std::string(),
83                                    signatureData.isAuthorSignature());
84         }
85
86         Result checkOutbound(const std::string &linkPath, const std::string &appPath)
87         {
88                 char resolvedPath[PATH_MAX];
89
90                 if (realpath((appPath + "/" + linkPath).c_str(), resolvedPath) == NULL)
91                         return ERROR_READING_LNK;
92
93                 std::string linkRealPath(resolvedPath);
94
95                 if (linkRealPath.compare(0, appPath.size(), appPath) == 0)
96                         return NO_ERROR;
97                 else
98                         return ERROR_OUTBOUND_LNK;
99         }
100
101 private:
102         int hexToInt(char hex);
103         std::string decodeProcent(const std::string &path);
104
105         Result dfsCheckDirectories(
106                 const ReferenceSet &referenceSet,
107                 const std::string &directory,
108                 bool isAuthorSignature);
109
110         inline bool isDistributorSignature(const char *cstring) const
111         {
112                 return m_signatureRegexp.FullMatch(cstring);
113         }
114
115         std::string m_dirpath;
116         pcrecpp::RE m_signatureRegexp;
117 };
118
119 int ReferenceValidator::Impl::hexToInt(char a)
120 {
121         if (a >= '0' && a <= '9') return a - '0';
122
123         if (a >= 'A' && a <= 'F') return a - 'A' + 10;
124
125         if (a >= 'a' && a <= 'f') return a - 'a' + 10;
126
127         LogError("Symbol '" << a << "' is out of scope.");
128         throw ERROR_DECODING_URL;
129 }
130
131 std::string ReferenceValidator::Impl::decodeProcent(const std::string &path)
132 {
133         std::vector<int> input(path.begin(), path.end());
134         std::vector<char> output;
135
136         try {
137                 size_t i = 0;
138
139                 while (i < input.size()) {
140                         if (MARK_ENCODED_CHAR == input[i]) {
141                                 if (i + 2 >= input.size())
142                                         throw ERROR_DECODING_URL;
143
144                                 int result = hexToInt(input[i + 1]) * 16 + hexToInt(input[i + 2]);
145                                 output.push_back(static_cast<char>(result));
146                                 i += 3;
147                         } else {
148                                 output.push_back(static_cast<char>(input[i]));
149                                 ++i;
150                         }
151                 }
152         } catch (Result &) {
153                 LogError("Error while decoding url path : " << path);
154                 throw ERROR_DECODING_URL;
155         }
156
157         return std::string(output.begin(), output.end());
158 }
159
160 ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories(
161         const ReferenceSet &referenceSet,
162         const std::string &directory,
163         bool isAuthorSignature)
164 {
165         int ret;
166         DIR *dirp;
167         struct dirent entry;
168         struct dirent *result;
169         std::string currentDir = m_dirpath;
170
171         if (!directory.empty()) {
172                 currentDir += "/";
173                 currentDir += directory;
174         }
175
176         if ((dirp = opendir(currentDir.c_str())) == NULL) {
177                 LogError("Error opening directory : " << currentDir);
178                 return ERROR_OPENING_DIR;
179         }
180
181         for (ret = readdir_r(dirp, &entry, &result);
182                         ret == 0 && result != NULL;
183                         ret = readdir_r(dirp, &entry, &result)) {
184                 if (!strcmp(result->d_name, SPECIAL_SYMBOL_CURRENT_DIR)) {
185                         continue;
186                 }
187
188                 if (!strcmp(result->d_name, SPECIAL_SYMBOL_UPPER_DIR)) {
189                         continue;
190                 }
191
192                 if (result->d_type == DT_UNKNOWN) {
193                         // try to stat inode when readdir is not returning known type
194                         std::string path = currentDir + "/" + result->d_name;
195                         struct stat s;
196
197                         if (lstat(path.c_str(), &s) != 0) {
198                                 closedir(dirp);
199                                 return ERROR_LSTAT;
200                         }
201
202                         if (S_ISREG(s.st_mode)) {
203                                 result->d_type = DT_REG;
204                         } else if (S_ISDIR(s.st_mode)) {
205                                 result->d_type = DT_DIR;
206                         }
207                 }
208
209                 if (currentDir == m_dirpath && result->d_type == DT_REG &&
210                                 !strcmp(result->d_name, SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE) &&
211                                 isAuthorSignature) {
212                         continue;
213                 }
214
215                 if (currentDir == m_dirpath && result->d_type == DT_REG &&
216                                 isDistributorSignature(result->d_name)) {
217                         continue;
218                 }
219
220                 if (result->d_type == DT_DIR) {
221                         LogDebug("Open directory : " << (directory + result->d_name));
222                         std::string tmp_directory = directory + result->d_name + "/";
223                         Result result = dfsCheckDirectories(referenceSet,
224                                                                                                 tmp_directory,
225                                                                                                 isAuthorSignature);
226
227                         if (result != NO_ERROR) {
228                                 closedir(dirp);
229                                 return result;
230                         }
231                 } else if (result->d_type == DT_REG) {
232                         if (referenceSet.end() ==
233                                         referenceSet.find(directory + result->d_name)) {
234                                 LogDebug("Found file : " << (directory + result->d_name));
235                                 LogError("Unknown ERROR_REFERENCE_NOT_FOUND.");
236                                 closedir(dirp);
237                                 return ERROR_REFERENCE_NOT_FOUND;
238                         }
239                 } else if (result->d_type == DT_LNK) {
240                         std::string linkPath(directory + result->d_name);
241
242                         if (referenceSet.end() ==
243                                         referenceSet.find(linkPath)) {
244                                 LogDebug("Found file : " << (directory + result->d_name));
245                                 LogError("Unknown ERROR_REFERENCE_NOT_FOUND.");
246                                 closedir(dirp);
247                                 return ERROR_REFERENCE_NOT_FOUND;
248                         }
249
250                         Result ret = checkOutbound(linkPath, m_dirpath);
251
252                         if (ret != NO_ERROR) {
253                                 LogError("Link file point wrong path");
254                                 closedir(dirp);
255                                 return ret;
256                         }
257                 } else {
258                         LogError("Unknown file type.");
259                         closedir(dirp);
260                         return ERROR_UNSUPPORTED_FILE_TYPE;
261                 }
262         }
263
264         if (ret != 0) {
265                 closedir(dirp);
266                 return ERROR_READING_DIR;
267         }
268
269         closedir(dirp);
270         return NO_ERROR;
271 }
272
273 ReferenceValidator::ReferenceValidator(const std::string &dirpath)
274         : m_impl(new Impl(dirpath))
275 {}
276
277 ReferenceValidator::~ReferenceValidator()
278 {
279         delete m_impl;
280 }
281
282 ReferenceValidator::Result ReferenceValidator::checkReferences(
283         const SignatureData &signatureData)
284 {
285         return m_impl->checkReferences(signatureData);
286 }
287
288 ReferenceValidator::Result ReferenceValidator::checkOutbound(
289         const std::string &linkPath, const std::string &appPath)
290 {
291         return m_impl->checkOutbound(linkPath, appPath);
292 }
293 } // ValidationCore