Replace deprecated readdir_r with readdir
[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 <limits.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #include <pcrecpp.h>
34
35 #include <dpl/log/log.h>
36
37 #ifndef PATH_MAX
38 #define PATH_MAX 4096
39 #endif
40
41 namespace ValidationCore {
42
43 namespace {
44
45 const char *AUTHOR_SIGNATURE = "author-signature.xml";
46 const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^signature[1-9][0-9]*\\.xml";
47 const char MARK_ENCODED_CHAR = '%';
48
49 struct dirent *readdir(DIR *dirp) {
50         errno = 0;
51         auto ret = ::readdir(dirp);
52         if (errno != 0)
53                 LogWarning("Error read dir.");
54         return ret;
55 }
56
57 } // anonymous namespace
58
59 class ReferenceValidator::Impl {
60 public:
61         Impl(const std::string &dirpath)
62                 : m_dirpath(dirpath)
63                 , m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE)
64         {}
65
66         virtual ~Impl() {}
67
68         Result checkReferences(const SignatureData &signatureData)
69         {
70                 const ReferenceSet &refSet = signatureData.getReferenceSet();
71                 ReferenceSet refDecoded;
72
73                 try {
74                         for (auto it = refSet.begin(); it != refSet.end(); ++it) {
75                                 if (std::string::npos != it->find(MARK_ENCODED_CHAR))
76                                         refDecoded.insert(decodeProcent(*it));
77                                 else
78                                         refDecoded.insert(*it);
79                         }
80                 } catch (Result &) {
81                         return ERROR_DECODING_URL;
82                 }
83
84                 return dfsCheckDirectories(
85                                    refDecoded,
86                                    std::string(),
87                                    signatureData.isAuthorSignature());
88         }
89
90         Result checkOutbound(const std::string &linkPath, const std::string &appPath)
91         {
92                 char resolvedPath[PATH_MAX];
93
94                 if (realpath((appPath + "/" + linkPath).c_str(), resolvedPath) == NULL)
95                         return ERROR_READING_LNK;
96
97                 std::string linkRealPath(resolvedPath);
98
99                 if (linkRealPath.compare(0, appPath.size(), appPath) == 0)
100                         return NO_ERROR;
101                 else
102                         return ERROR_OUTBOUND_LNK;
103         }
104
105 private:
106         int hexToInt(char hex);
107         std::string decodeProcent(const std::string &path);
108
109         Result dfsCheckDirectories(
110                 const ReferenceSet &referenceSet,
111                 const std::string &directory,
112                 bool isAuthorSignature);
113
114         inline bool isDistributorSignature(const char *cstring) const
115         {
116                 return m_signatureRegexp.FullMatch(cstring);
117         }
118
119         std::string m_dirpath;
120         pcrecpp::RE m_signatureRegexp;
121 };
122
123 int ReferenceValidator::Impl::hexToInt(char a)
124 {
125         if (a >= '0' && a <= '9') return a - '0';
126
127         if (a >= 'A' && a <= 'F') return a - 'A' + 10;
128
129         if (a >= 'a' && a <= 'f') return a - 'a' + 10;
130
131         LogError("Symbol '" << a << "' is out of scope.");
132         throw ERROR_DECODING_URL;
133 }
134
135 std::string ReferenceValidator::Impl::decodeProcent(const std::string &path)
136 {
137         std::vector<int> input(path.begin(), path.end());
138         std::vector<char> output;
139
140         try {
141                 size_t i = 0;
142
143                 while (i < input.size()) {
144                         if (MARK_ENCODED_CHAR == input[i]) {
145                                 if (i + 2 >= input.size())
146                                         throw ERROR_DECODING_URL;
147
148                                 int result = hexToInt(input[i + 1]) * 16 + hexToInt(input[i + 2]);
149                                 output.push_back(static_cast<char>(result));
150                                 i += 3;
151                         } else {
152                                 output.push_back(static_cast<char>(input[i]));
153                                 ++i;
154                         }
155                 }
156         } catch (Result &) {
157                 LogError("Error while decoding url path : " << path);
158                 throw ERROR_DECODING_URL;
159         }
160
161         return std::string(output.begin(), output.end());
162 }
163
164 ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories(
165         const ReferenceSet &referenceSet,
166         const std::string &directory,
167         bool isAuthorSignature)
168 {
169         std::string currentDir = m_dirpath;
170         if (!directory.empty())
171                 currentDir += ("/" + directory);
172
173         std::unique_ptr<DIR, std::function<int(DIR *)>> dp(::opendir(currentDir.c_str()),
174                                                                                                            ::closedir);
175         if (dp == nullptr) {
176                 LogError("Error opening directory : " << currentDir);
177                 return ERROR_OPENING_DIR;
178         }
179
180         while (auto dirp = ValidationCore::readdir(dp.get())) {
181                 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
182                         continue;
183
184                 if (dirp->d_type == DT_UNKNOWN) {
185                         // try to stat inode when readdir is not returning known type
186                         std::string path = currentDir + "/" + dirp->d_name;
187                         struct stat s;
188                         if (lstat(path.c_str(), &s) != 0)
189                                 return ERROR_LSTAT;
190
191                         if (S_ISREG(s.st_mode))
192                                 dirp->d_type = DT_REG;
193                         else if (S_ISDIR(s.st_mode))
194                                 dirp->d_type = DT_DIR;
195                 }
196
197                 if (currentDir == m_dirpath && dirp->d_type == DT_REG)
198                         if ((!strcmp(dirp->d_name, AUTHOR_SIGNATURE) && isAuthorSignature) ||
199                                 isDistributorSignature(dirp->d_name))
200                                 continue;
201
202                 if (dirp->d_type == DT_DIR) {
203                         LogDebug("Open directory : " << (directory + dirp->d_name));
204                         std::string tmp_directory = directory + dirp->d_name + "/";
205                         Result result = dfsCheckDirectories(referenceSet,
206                                                                                                 tmp_directory,
207                                                                                                 isAuthorSignature);
208                         if (result != NO_ERROR)
209                                 return result;
210                 } else if (dirp->d_type == DT_REG) {
211                         if (referenceSet.end() == referenceSet.find(directory + dirp->d_name)) {
212                                 LogError("Cannot find : " << (directory + dirp->d_name));
213                                 return ERROR_REFERENCE_NOT_FOUND;
214                         }
215                 } else if (dirp->d_type == DT_LNK) {
216                         std::string linkPath(directory + dirp->d_name);
217                         if (referenceSet.end() == referenceSet.find(linkPath)) {
218                                 LogError("Cannot find : " << (directory + dirp->d_name));
219                                 return ERROR_REFERENCE_NOT_FOUND;
220                         }
221
222                         Result result = checkOutbound(linkPath, m_dirpath);
223                         if (result != NO_ERROR) {
224                                 LogError("Link file point wrong path. : " << linkPath);
225                                 return result;
226                         }
227                 } else {
228                         LogError("Unknown file type.");
229                         return ERROR_UNSUPPORTED_FILE_TYPE;
230                 }
231         }
232
233
234
235         return NO_ERROR;
236 }
237
238 ReferenceValidator::ReferenceValidator(const std::string &dirpath)
239         : m_impl(new Impl(dirpath))
240 {}
241
242 ReferenceValidator::~ReferenceValidator()
243 {
244         delete m_impl;
245 }
246
247 ReferenceValidator::Result ReferenceValidator::checkReferences(
248         const SignatureData &signatureData)
249 {
250         return m_impl->checkReferences(signatureData);
251 }
252
253 ReferenceValidator::Result ReferenceValidator::checkOutbound(
254         const std::string &linkPath, const std::string &appPath)
255 {
256         return m_impl->checkOutbound(linkPath, appPath);
257 }
258 } // ValidationCore