Refactor log system
[platform/core/security/cert-svc.git] / vcore / src / vcore / ReferenceValidator.cpp
1 /*
2  * Copyright (c) 2011 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  * @file        ReferenceValidator.cpp
19  * @version     1.0
20  * @brief       Compare signature reference list and list of widget file.
21  */
22 #include <vcore/ReferenceValidator.h>
23
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fstream>
27 #include <memory>
28
29 #include <pcrecpp.h>
30
31 #include <dpl/errno_string.h>
32 #include <dpl/log/log.h>
33
34 namespace {
35
36 const char *SPECIAL_SYMBOL_CURRENT_DIR = ".";
37 const char *SPECIAL_SYMBOL_UPPER_DIR = "..";
38 const char *SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE = "author-signature.xml";
39 const char *REGEXP_DISTRIBUTOR_SIGNATURE = "^signature[1-9][0-9]*\\.xml";
40
41 const char MARK_ENCODED_CHAR = '%';
42
43 } // namespace anonymous
44
45 namespace ValidationCore {
46
47 class ReferenceValidator::Impl
48 {
49   public:
50     Impl(const std::string &dirpath)
51       : m_dirpath(dirpath)
52       , m_signatureRegexp(REGEXP_DISTRIBUTOR_SIGNATURE)
53     {}
54
55     virtual ~Impl(){}
56
57     Result checkReferences(const SignatureData &signatureData){
58         const ReferenceSet &refSet = signatureData.getReferenceSet();
59         ReferenceSet refDecoded;
60
61         try {
62             for (auto it = refSet.begin(); it != refSet.end(); ++it) {
63                 if (std::string::npos != it->find(MARK_ENCODED_CHAR))
64                     refDecoded.insert(decodeProcent(*it));
65                 else
66                     refDecoded.insert(*it);
67             }
68         } catch (Result &) {
69             return ERROR_DECODING_URL;
70         }
71         return dfsCheckDirectories(
72             refDecoded,
73             std::string(),
74             signatureData.isAuthorSignature());
75     }
76
77   private:
78     int hexToInt(char hex);
79     std::string decodeProcent(const std::string &path);
80
81     Result dfsCheckDirectories(
82         const ReferenceSet &referenceSet,
83         const std::string &directory,
84         bool isAuthorSignature);
85
86     inline bool isDistributorSignature(const char *cstring) const
87     {
88         return m_signatureRegexp.FullMatch(cstring);
89     }
90
91     std::string m_dirpath;
92     std::string m_errorDescription;
93     pcrecpp::RE m_signatureRegexp;
94 };
95
96 int ReferenceValidator::Impl::hexToInt(char a) {
97     if (a >= '0' && a <= '9') return a-'0';
98     if (a >= 'A' && a <= 'F') return a-'A' + 10;
99     if (a >= 'a' && a <= 'f') return a-'a' + 10;
100     LogError("Symbol '" << a << "' is out of scope.");
101     throw ERROR_DECODING_URL;
102 }
103
104 std::string ReferenceValidator::Impl::decodeProcent(const std::string &path) {
105     std::vector<int> input(path.begin(), path.end());
106     std::vector<char> output;
107     try {
108         size_t i = 0;
109         while(i<input.size()) {
110             if (MARK_ENCODED_CHAR == input[i]) {
111                 if (i+2 >= input.size())
112                     throw ERROR_DECODING_URL;
113
114                 int result = hexToInt(input[i+1])*16 + hexToInt(input[i+2]);
115
116                 // RFC 1738 - octets 80 to FF are not allowed
117                 if (result >= 128)
118                     throw ERROR_DECODING_URL;
119
120                 output.push_back(static_cast<char>(result));
121                 i+=3;
122             } else {
123                 output.push_back(static_cast<char>(input[i]));
124                 ++i;
125             }
126         }
127     } catch (Result &) {
128         LogError("Error while decoding url path : " << path);
129         throw ERROR_DECODING_URL;
130     }
131     return std::string(output.begin(), output.end());
132 }
133
134 ReferenceValidator::Result ReferenceValidator::Impl::dfsCheckDirectories(
135     const ReferenceSet &referenceSet,
136     const std::string &directory,
137     bool isAuthorSignature)
138 {
139     DIR *dp;
140     struct dirent *dirp;
141     std::string currentDir = m_dirpath + directory;
142
143     if ((dp = opendir(currentDir.c_str())) == NULL) {
144         LogError("Error opening directory : " << currentDir);
145         m_errorDescription = currentDir;
146         return ERROR_OPENING_DIR;
147     }
148
149     for (errno = 0; (dirp = readdir(dp)) != NULL; errno = 0) {
150         if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_CURRENT_DIR)) {
151             continue;
152         }
153
154         if (!strcmp(dirp->d_name, SPECIAL_SYMBOL_UPPER_DIR)) {
155             continue;
156         }
157
158         if (currentDir == m_dirpath && dirp->d_type == DT_REG &&
159             !strcmp(dirp->d_name, SPECIAL_SYMBOL_AUTHOR_SIGNATURE_FILE) &&
160             isAuthorSignature)
161         {
162             continue;
163         }
164
165         if (currentDir == m_dirpath && dirp->d_type == DT_REG &&
166             isDistributorSignature(dirp->d_name)) {
167             continue;
168         }
169
170         if (dirp->d_type == DT_DIR) {
171             LogDebug("Open directory : " << (directory + dirp->d_name));
172             std::string tmp_directory = directory + dirp->d_name + "/";
173             Result result = dfsCheckDirectories(referenceSet,
174                                                 tmp_directory,
175                                                 isAuthorSignature);
176             if (result != NO_ERROR) {
177                 closedir(dp);
178                 return result;
179             }
180         } else if (dirp->d_type == DT_REG) {
181             if (referenceSet.end() ==
182                 referenceSet.find(directory + dirp->d_name))
183             {
184                 LogDebug("Found file : " << (directory + dirp->d_name));
185                 LogError("Unknown ERROR_REFERENCE_NOT_FOUND.");
186                 closedir(dp);
187                 m_errorDescription = directory + dirp->d_name;
188                 return ERROR_REFERENCE_NOT_FOUND;
189             }
190         } else {
191             LogError("Unknown file type.");
192             closedir(dp);
193             m_errorDescription = directory + dirp->d_name;
194             return ERROR_UNSUPPORTED_FILE_TYPE;
195         }
196     }
197
198     if (errno != 0) {
199         m_errorDescription = VcoreDPL::GetErrnoString();
200         LogError("readdir failed. Errno code : " << errno << ", Description : " << m_errorDescription);
201         closedir(dp);
202         return ERROR_READING_DIR;
203     }
204
205     closedir(dp);
206
207     return NO_ERROR;
208 }
209
210 ReferenceValidator::ReferenceValidator(const std::string &dirpath)
211   : m_impl(new Impl(dirpath))
212 {}
213
214 ReferenceValidator::~ReferenceValidator(){
215     delete m_impl;
216 }
217
218 ReferenceValidator::Result ReferenceValidator::checkReferences(
219     const SignatureData &signatureData)
220 {
221     return m_impl->checkReferences(signatureData);
222 }
223
224 } // ValidationCore